1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-28 00:04:05 +02:00

adds timer unit to ifxmips tree

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11530 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
blogic 2008-06-17 22:14:08 +00:00
parent 60203de0fb
commit bbfaf569cc
8 changed files with 1484 additions and 13 deletions

View File

@ -1,5 +1,2 @@
obj-y := reset.o prom.o setup.o interrupt.o dma-core.o pmu.o board.o
#mps/
obj-y := reset.o prom.o setup.o interrupt.o dma-core.o pmu.o board.o cgu.o gptu.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_KGDB) += kgdb_serial.o

View File

@ -35,7 +35,7 @@
#include <asm/io.h>
#include <asm/ifxmips/ifxmips.h>
#define MAX_IFXMIPS_DEVS 6
#define MAX_IFXMIPS_DEVS 7
#define BOARD_DANUBE "Danube"
#define BOARD_DANUBE_CHIPID 0x10129083
@ -73,6 +73,14 @@ static struct platform_device ifxmips_mii[] =
},
};
static struct platform_device ifxmips_wdt[] =
{
{
.id = 0,
.name = "ifxmips_wdt",
},
};
static struct physmap_flash_data ifxmips_mtd_data = {
.width = 2,
};
@ -148,6 +156,7 @@ int __init ifxmips_init_devices(void)
ifxmips_devs[dev++] = ifxmips_gpio;
ifxmips_devs[dev++] = ifxmips_mii;
ifxmips_devs[dev++] = ifxmips_mtd;
ifxmips_devs[dev++] = ifxmips_wdt;
#ifdef CONFIG_GPIO_DEVICE
ifxmips_devs[dev++] = ifxmips_gpio_dev;
#endif

View File

@ -0,0 +1,396 @@
/*
* arch/mips/ifxmips/cgu.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) 2007 Xu Liang, infineon
*
* Rewrite of Infineon IFXMips code
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/irq.h>
#include <asm/div64.h>
#include <linux/errno.h>
#include <asm/ifxmips/ifxmips.h>
#define FIX_FOR_36M_CRYSTAL 1
#define BASIC_INPUT_CLOCK_FREQUENCY_1 35328000
#define BASIC_INPUT_CLOCK_FREQUENCY_2 36000000
#define BASIS_INPUT_CRYSTAL_USB 12000000
#define GET_BITS(x, msb, lsb) (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
#define SET_BITS(x, msb, lsb, value) (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
#define CGU_PLL0_PHASE_DIVIDER_ENABLE (*IFXMIPS_CGU_PLL0_CFG & (1 << 31))
#define CGU_PLL0_BYPASS (*IFXMIPS_CGU_PLL0_CFG & (1 << 30))
#define CGU_PLL0_SRC (*IFXMIPS_CGU_PLL0_CFG & (1 << 29))
#define CGU_PLL0_CFG_DSMSEL (*IFXMIPS_CGU_PLL0_CFG & (1 << 28))
#define CGU_PLL0_CFG_FRAC_EN (*IFXMIPS_CGU_PLL0_CFG & (1 << 27))
#define CGU_PLL0_CFG_PLLK GET_BITS(*IFXMIPS_CGU_PLL0_CFG, 26, 17)
#define CGU_PLL0_CFG_PLLN GET_BITS(*IFXMIPS_CGU_PLL0_CFG, 12, 6)
#define CGU_PLL0_CFG_PLLM GET_BITS(*IFXMIPS_CGU_PLL0_CFG, 5, 2)
#define CGU_PLL1_SRC (*IFXMIPS_CGU_PLL1_CFG & (1 << 31))
#define CGU_PLL1_BYPASS (*IFXMIPS_CGU_PLL1_CFG & (1 << 30))
#define CGU_PLL1_CFG_DSMSEL (*IFXMIPS_CGU_PLL1_CFG & (1 << 28))
#define CGU_PLL1_CFG_FRAC_EN (*IFXMIPS_CGU_PLL1_CFG & (1 << 27))
#define CGU_PLL1_CFG_PLLK GET_BITS(*IFXMIPS_CGU_PLL1_CFG, 26, 17)
#define CGU_PLL1_CFG_PLLN GET_BITS(*IFXMIPS_CGU_PLL1_CFG, 12, 6)
#define CGU_PLL1_CFG_PLLM GET_BITS(*IFXMIPS_CGU_PLL1_CFG, 5, 2)
#define CGU_PLL2_PHASE_DIVIDER_ENABLE (*IFXMIPS_CGU_PLL2_CFG & (1 << 20))
#define CGU_PLL2_BYPASS (*IFXMIPS_CGU_PLL2_CFG & (1 << 19))
#define CGU_PLL2_SRC GET_BITS(*IFXMIPS_CGU_PLL2_CFG, 18, 17)
#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(*IFXMIPS_CGU_PLL2_CFG, 16, 13)
#define CGU_PLL2_CFG_PLLN GET_BITS(*IFXMIPS_CGU_PLL2_CFG, 12, 6)
#define CGU_PLL2_CFG_PLLM GET_BITS(*IFXMIPS_CGU_PLL2_CFG, 5, 2)
#define CGU_SYS_PPESEL GET_BITS(*IFXMIPS_CGU_SYS, 8, 7)
#define CGU_SYS_FPI_SEL (*IFXMIPS_CGU_SYS & (1 << 6))
#define CGU_SYS_CPU1SEL GET_BITS(*IFXMIPS_CGU_SYS, 5, 4)
#define CGU_SYS_CPU0SEL GET_BITS(*IFXMIPS_CGU_SYS, 3, 2)
#define CGU_SYS_DDR_SEL GET_BITS(*IFXMIPS_CGU_SYS, 1, 0)
#define CGU_IF_CLK_PCI_CLK GET_BITS(*IFXMIPS_CGU_IF_CLK, 23, 20)
#define CGU_IF_CLK_USBSEL GET_BITS(*IFXMIPS_CGU_IF_CLK, 5, 4)
#define CGU_IF_CLK_MIISEL GET_BITS(*IFXMIPS_CGU_IF_CLK, 1, 0)
static u32 cgu_get_pll0_fdiv(void);
static inline u32 get_input_clock(int pll)
{
switch(pll)
{
case 0:
if(CGU_PLL0_SRC)
return BASIS_INPUT_CRYSTAL_USB;
else if(CGU_PLL0_PHASE_DIVIDER_ENABLE)
return BASIC_INPUT_CLOCK_FREQUENCY_1;
else
return BASIC_INPUT_CLOCK_FREQUENCY_2;
case 1:
if(CGU_PLL1_SRC)
return BASIS_INPUT_CRYSTAL_USB;
else if(CGU_PLL0_PHASE_DIVIDER_ENABLE)
return BASIC_INPUT_CLOCK_FREQUENCY_1;
else
return BASIC_INPUT_CLOCK_FREQUENCY_2;
case 2:
switch(CGU_PLL2_SRC)
{
case 0:
return cgu_get_pll0_fdiv();
case 1:
return CGU_PLL2_PHASE_DIVIDER_ENABLE ? BASIC_INPUT_CLOCK_FREQUENCY_1 : BASIC_INPUT_CLOCK_FREQUENCY_2;
case 2:
return BASIS_INPUT_CRYSTAL_USB;
}
default:
return 0;
}
}
static inline u32
cal_dsm(int pll, u32 num, u32 den)
{
u64 res, clock = get_input_clock(pll);
res = num * clock;
do_div(res, den);
return res;
}
static inline u32
mash_dsm(int pll, u32 M, u32 N, u32 K)
{
u32 num = ((N + 1) << 10) + K;
u32 den = (M + 1) << 10;
return cal_dsm(pll, num, den);
}
static inline u32 ssff_dsm_1(int pll, u32 M, u32 N, u32 K)
{
u32 num = ((N + 1) << 11) + K + 512;
u32 den = (M + 1) << 11;
return cal_dsm(pll, num, den);
}
static inline u32 ssff_dsm_2(int pll, u32 M, u32 N, u32 K)
{
u32 num = K >= 512 ? ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
u32 den = (M + 1) << 12;
return cal_dsm(pll, num, den);
}
static inline u32 dsm(int pll, u32 M, u32 N, u32 K, u32 dsmsel, u32 phase_div_en)
{
if ( !dsmsel )
return mash_dsm(pll, M, N, K);
else if ( !phase_div_en )
return mash_dsm(pll, M, N, K);
else
return ssff_dsm_2(pll, M, N, K);
}
static inline u32 cgu_get_pll0_fosc(void)
{
if(CGU_PLL0_BYPASS)
return get_input_clock(0);
else
return !CGU_PLL0_CFG_FRAC_EN
? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, CGU_PLL0_CFG_DSMSEL, CGU_PLL0_PHASE_DIVIDER_ENABLE)
: dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, CGU_PLL0_PHASE_DIVIDER_ENABLE);
}
static inline u32 cgu_get_pll0_fps(int phase)
{
register u32 fps = cgu_get_pll0_fosc();
switch ( phase )
{
case 1:
/* 1.25 */
fps = ((fps << 2) + 2) / 5;
break;
case 2:
/* 1.5 */
fps = ((fps << 1) + 1) / 3;
break;
}
return fps;
}
static u32 cgu_get_pll0_fdiv(void)
{
register u32 div = CGU_PLL2_CFG_INPUT_DIV + 1;
return (cgu_get_pll0_fosc() + (div >> 1)) / div;
}
static inline u32 cgu_get_pll1_fosc(void)
{
if(CGU_PLL1_BYPASS)
return get_input_clock(1);
else
return !CGU_PLL1_CFG_FRAC_EN
? dsm(1, CGU_PLL1_CFG_PLLM, CGU_PLL1_CFG_PLLN, 0, CGU_PLL1_CFG_DSMSEL, 0)
: dsm(1, CGU_PLL1_CFG_PLLM, CGU_PLL1_CFG_PLLN, CGU_PLL1_CFG_PLLK, CGU_PLL1_CFG_DSMSEL, 0);
}
static inline u32 cgu_get_pll1_fps(void)
{
register u32 fps = cgu_get_pll1_fosc();
return ((fps << 1) + 1) / 3;
}
static inline u32 cgu_get_pll1_fdiv(void)
{
return cgu_get_pll1_fosc();
}
static inline u32 cgu_get_pll2_fosc(void)
{
u64 res, clock = get_input_clock(2);
if ( CGU_PLL2_BYPASS )
return get_input_clock(2);
res = (CGU_PLL2_CFG_PLLN + 1) * clock;
do_div(res, CGU_PLL2_CFG_PLLM + 1);
return res;
}
static inline u32 cgu_get_pll2_fps(int phase)
{
register u32 fps = cgu_get_pll2_fosc();
switch ( phase )
{
case 1:
/* 1.125 */
fps = ((fps << 2) + 2) / 5; break;
case 2:
/* 1.25 */
fps = ((fps << 3) + 4) / 9;
}
return fps;
}
static inline u32 cgu_get_pll2_fdiv(void)
{
register u32 div = CGU_IF_CLK_PCI_CLK + 1;
return (cgu_get_pll2_fosc() + (div >> 1)) / div;
}
u32 cgu_get_mips_clock(int cpu)
{
register u32 ret = cgu_get_pll0_fosc();
register u32 cpusel = cpu == 0 ? CGU_SYS_CPU0SEL : CGU_SYS_CPU1SEL;
if ( cpusel == 0 )
return ret;
else if ( cpusel == 2 )
ret <<= 1;
switch ( CGU_SYS_DDR_SEL )
{
default:
case 0:
return (ret + 1) / 2;
case 1:
return (ret * 2 + 2) / 5;
case 2:
return (ret + 1) / 3;
case 3:
return (ret + 2) / 4;
}
}
u32 cgu_get_cpu_clock(void)
{
return cgu_get_mips_clock(0);
}
u32 cgu_get_io_region_clock(void)
{
register u32 ret = cgu_get_pll0_fosc();
switch ( CGU_SYS_DDR_SEL )
{
default:
case 0:
return (ret + 1) / 2;
case 1:
return (ret * 2 + 2) / 5;
case 2:
return (ret + 1) / 3;
case 3:
return (ret + 2) / 4;
}
}
u32 cgu_get_fpi_bus_clock(int fpi)
{
register u32 ret = cgu_get_io_region_clock();
if((fpi == 2) && (CGU_SYS_FPI_SEL))
ret >>= 1;
return ret;
}
u32 cgu_get_pp32_clock(void)
{
switch ( CGU_SYS_PPESEL )
{
default:
case 0:
return cgu_get_pll2_fps(1);
case 1:
return cgu_get_pll2_fps(2);
case 2:
return (cgu_get_pll2_fps(1) + 1) >> 1;
case 3:
return (cgu_get_pll2_fps(2) + 1) >> 1;
}
}
u32 cgu_get_ethernet_clock(int mii)
{
switch ( CGU_IF_CLK_MIISEL )
{
case 0:
return (cgu_get_pll2_fosc() + 3) / 12;
case 1:
return (cgu_get_pll2_fosc() + 3) / 6;
case 2:
return 50000000;
case 3:
return 25000000;
}
return 0;
}
u32 cgu_get_usb_clock(void)
{
switch ( CGU_IF_CLK_USBSEL )
{
case 0:
return (cgu_get_pll2_fosc() + 12) / 25;
case 1:
return 12000000;
case 2:
return 12000000 / 4;
case 3:
return 12000000;
}
return 0;
}
u32 cgu_get_clockout(int clkout)
{
u32 fosc1 = cgu_get_pll1_fosc();
u32 fosc2 = cgu_get_pll2_fosc();
if ( clkout > 3 || clkout < 0 )
return 0;
switch ( ((u32)clkout << 2) | GET_BITS(*IFXMIPS_CGU_IF_CLK, 15 - clkout * 2, 14 - clkout * 2) )
{
case 0: /* 32.768KHz */
case 15:
return (fosc1 + 6000) / 12000;
case 1: /* 1.536MHz */
return (fosc1 + 128) / 256;
case 2: /* 2.5MHz */
return (fosc2 + 60) / 120;
case 3: /* 12MHz */
case 5:
case 12:
return (fosc2 + 12) / 25;
case 4: /* 40MHz */
return (cgu_get_pll2_fps(2) + 3) / 6;
case 6: /* 24MHz */
return (cgu_get_pll2_fps(2) + 5) / 10;
case 7: /* 48MHz */
return (cgu_get_pll2_fps(2) + 2) / 5;
case 8: /* 25MHz */
case 14:
return (fosc2 + 6) / 12;
case 9: /* 50MHz */
case 13:
return (fosc2 + 3) / 6;
case 10:/* 30MHz */
return (fosc2 + 5) / 10;
case 11:/* 60MHz */
return (fosc2 + 2) / 5;
}
return 0;
}

View File

@ -0,0 +1,846 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/irq.h>
#include <asm/div64.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <asm/ifxmips/ifxmips.h>
#include <asm/ifxmips/ifxmips_irq.h>
#include <asm/ifxmips/ifxmips_cgu.h>
#include <asm/ifxmips/ifxmips_gptu.h>
#include <asm/ifxmips/ifxmips_pmu.h>
#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6
#ifdef TIMER1A
#define FIRST_TIMER TIMER1A
#else
#define FIRST_TIMER 2
#endif
/*
* GPTC divider is set or not.
*/
#define GPTU_CLC_RMC_IS_SET 0
/*
* Timer Interrupt (IRQ)
*/
#define TIMER_INTERRUPT INT_NUM_IM3_IRL0 + 22 // Must be adjusted when ICU driver is available
/*
* Bits Operation
*/
#define GET_BITS(x, msb, lsb) (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
#define SET_BITS(x, msb, lsb, value) (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
/*
* GPTU Register Mapping
*/
#define IFXMIPS_GPTU (KSEG1 + 0x1E100A00)
#define IFXMIPS_GPTU_CLC ((volatile u32*)(IFXMIPS_GPTU + 0x0000))
#define IFXMIPS_GPTU_ID ((volatile u32*)(IFXMIPS_GPTU + 0x0008))
#define IFXMIPS_GPTU_CON(n, X) ((volatile u32*)(IFXMIPS_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) // X must be either A or B
#define IFXMIPS_GPTU_RUN(n, X) ((volatile u32*)(IFXMIPS_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) // X must be either A or B
#define IFXMIPS_GPTU_RELOAD(n, X) ((volatile u32*)(IFXMIPS_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) // X must be either A or B
#define IFXMIPS_GPTU_COUNT(n, X) ((volatile u32*)(IFXMIPS_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) // X must be either A or B
#define IFXMIPS_GPTU_IRNEN ((volatile u32*)(IFXMIPS_GPTU + 0x00F4))
#define IFXMIPS_GPTU_IRNICR ((volatile u32*)(IFXMIPS_GPTU + 0x00F8))
#define IFXMIPS_GPTU_IRNCR ((volatile u32*)(IFXMIPS_GPTU + 0x00FC))
/*
* Clock Control Register
*/
#define GPTU_CLC_SMC GET_BITS(*IFXMIPS_GPTU_CLC, 23, 16)
#define GPTU_CLC_RMC GET_BITS(*IFXMIPS_GPTU_CLC, 15, 8)
#define GPTU_CLC_FSOE (*IFXMIPS_GPTU_CLC & (1 << 5))
#define GPTU_CLC_EDIS (*IFXMIPS_GPTU_CLC & (1 << 3))
#define GPTU_CLC_SPEN (*IFXMIPS_GPTU_CLC & (1 << 2))
#define GPTU_CLC_DISS (*IFXMIPS_GPTU_CLC & (1 << 1))
#define GPTU_CLC_DISR (*IFXMIPS_GPTU_CLC & (1 << 0))
#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value))
#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value))
#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0)
#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0)
#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0)
#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0)
#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0)
/*
* ID Register
*/
#define GPTU_ID_ID GET_BITS(*IFXMIPS_GPTU_ID, 15, 8)
#define GPTU_ID_CFG GET_BITS(*IFXMIPS_GPTU_ID, 7, 5)
#define GPTU_ID_REV GET_BITS(*IFXMIPS_GPTU_ID, 4, 0)
/*
* Control Register of Timer/Counter nX
* n is the index of block (1 based index)
* X is either A or B
*/
#define GPTU_CON_SRC_EG(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 10))
#define GPTU_CON_SRC_EXT(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 9))
#define GPTU_CON_SYNC(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 8))
#define GPTU_CON_EDGE(n, X) GET_BITS(*IFXMIPS_GPTU_CON(n, X), 7, 6)
#define GPTU_CON_INV(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 5))
#define GPTU_CON_EXT(n, X) (*IFXMIPS_GPTU_CON(n, A) & (1 << 4)) // Timer/Counter B does not have this bit
#define GPTU_CON_STP(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 3))
#define GPTU_CON_CNT(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 2))
#define GPTU_CON_DIR(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 1))
#define GPTU_CON_EN(n, X) (*IFXMIPS_GPTU_CON(n, X) & (1 << 0))
#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10))
#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0)
#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0)
#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value))
#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0)
#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0)
#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0)
#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0)
#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0)
#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0)
#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0)
#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0)
#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001)
#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002)
#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004)
#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008)
#define TIMER_FLAG_NONE_EDGE 0x0000
#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030)
#define TIMER_FLAG_REAL 0x0000
#define TIMER_FLAG_INVERT 0x0040
#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040)
#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070)
#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080)
#define TIMER_FLAG_CALLBACK_IN_HB 0x0200
#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300)
#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000)
struct timer_dev_timer {
unsigned int f_irq_on;
unsigned int irq;
unsigned int flag;
unsigned long arg1;
unsigned long arg2;
};
struct timer_dev {
struct mutex gptu_mutex;
unsigned int number_of_timers;
unsigned int occupation;
unsigned int f_gptu_on;
struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2];
};
static int gptu_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
static int gptu_open(struct inode *, struct file *);
static int gptu_release(struct inode *, struct file *);
static struct file_operations gptu_fops = {
.owner = THIS_MODULE,
.ioctl = gptu_ioctl,
.open = gptu_open,
.release = gptu_release
};
static struct miscdevice gptu_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "gptu",
.fops = &gptu_fops,
};
static struct timer_dev timer_dev;
static irqreturn_t
timer_irq_handler(int irq, void *p)
{
unsigned int timer;
unsigned int flag;
struct timer_dev_timer *dev_timer = (struct timer_dev_timer*) p;
timer = irq - TIMER_INTERRUPT;
if(timer < timer_dev.number_of_timers && dev_timer == &timer_dev.timer[timer])
{
/* Clear interrupt. */
ifxmips_w32(1 << timer, IFXMIPS_GPTU_IRNCR);
/* Call user hanler or signal. */
flag = dev_timer->flag;
if (!(timer & 0x01) || TIMER_FLAG_MASK_SIZE (flag) == TIMER_FLAG_16BIT)
{ /* 16-bit timer or timer A of 32-bit timer */
switch(TIMER_FLAG_MASK_HANDLE (flag))
{
case TIMER_FLAG_CALLBACK_IN_IRQ:
case TIMER_FLAG_CALLBACK_IN_HB:
if (dev_timer->arg1)
(*(timer_callback) dev_timer->arg1) (dev_timer->arg2);
break;
case TIMER_FLAG_SIGNAL:
send_sig ((int) dev_timer->arg2, (struct task_struct *) dev_timer->arg1, 0);
break;
}
}
}
return IRQ_HANDLED;
}
static inline void
ifxmips_enable_gptu(void)
{
ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_GPT);
/* Set divider as 1, disable write protection for SPEN, enable module. */
*IFXMIPS_GPTU_CLC =
GPTU_CLC_SMC_SET(0x00) | GPTU_CLC_RMC_SET(0x01) | GPTU_CLC_FSOE_SET(0) |
GPTU_CLC_SBWE_SET(1) | GPTU_CLC_EDIS_SET(0) | GPTU_CLC_SPEN_SET(0) | GPTU_CLC_DISR_SET(0);
}
static inline void
ifxmips_disable_gptu(void)
{
ifxmips_w32(0x00, IFXMIPS_GPTU_IRNEN);
ifxmips_w32(0xfff, IFXMIPS_GPTU_IRNCR);
/* Set divider as 0, enable write protection for SPEN, disable module. */
*IFXMIPS_GPTU_CLC =
GPTU_CLC_SMC_SET (0x00) | GPTU_CLC_RMC_SET (0x00) | GPTU_CLC_FSOE_SET (0) |
GPTU_CLC_SBWE_SET (0) | GPTU_CLC_EDIS_SET (0) | GPTU_CLC_SPEN_SET (0) | GPTU_CLC_DISR_SET (1);
ifxmips_pmu_disable(IFXMIPS_PMU_PWDCR_GPT);
}
int
ifxmips_request_timer(unsigned int timer, unsigned int flag, unsigned long value,
unsigned long arg1, unsigned long arg2)
{
int ret = 0;
unsigned int con_reg, irnen_reg;
int n, X;
if(timer >= FIRST_TIMER + timer_dev.number_of_timers)
return -EINVAL;
printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...", (u32)timer, (u32)flag, value);
if(TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT)
value &= 0xFFFF;
else
timer &= ~0x01;
mutex_lock(&timer_dev.gptu_mutex);
/*
* Allocate timer.
*/
if (timer < FIRST_TIMER) {
unsigned int mask;
unsigned int shift;
unsigned int offset = TIMER2A;/* This takes care of TIMER1B which is the only choice for Voice TAPI system */
/*
* Pick up a free timer.
*/
if (TIMER_FLAG_MASK_SIZE (flag) == TIMER_FLAG_16BIT) {
mask = 1 << offset;
shift = 1;
}
else {
mask = 3 << offset;
shift = 2;
}
for (timer = offset;
timer < offset + timer_dev.number_of_timers;
timer += shift, mask <<= shift)
if (!(timer_dev.occupation & mask)) {
timer_dev.occupation |= mask;
break;
}
if (timer >= offset + timer_dev.number_of_timers) {
printk("failed![%d]\n", __LINE__);
mutex_unlock(&timer_dev.gptu_mutex);
return -EINVAL;
}
else
ret = timer;
}
else {
register unsigned int mask;
/*
* Check if the requested timer is free.
*/
mask = (TIMER_FLAG_MASK_SIZE (flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
if ((timer_dev.occupation & mask)) {
printk("failed![%d] mask %#x, timer_dev.occupation %#x\n", __LINE__, mask, timer_dev.occupation);
mutex_unlock(&timer_dev.gptu_mutex);
return -EBUSY;
}
else {
timer_dev.occupation |= mask;
ret = 0;
}
}
/*
* Prepare control register value.
*/
switch (TIMER_FLAG_MASK_EDGE (flag)) {
default:
case TIMER_FLAG_NONE_EDGE:
con_reg = GPTU_CON_EDGE_SET (0x00);
break;
case TIMER_FLAG_RISE_EDGE:
con_reg = GPTU_CON_EDGE_SET (0x01);
break;
case TIMER_FLAG_FALL_EDGE:
con_reg = GPTU_CON_EDGE_SET (0x02);
break;
case TIMER_FLAG_ANY_EDGE:
con_reg = GPTU_CON_EDGE_SET (0x03);
break;
}
if (TIMER_FLAG_MASK_TYPE (flag) == TIMER_FLAG_TIMER)
con_reg |=
TIMER_FLAG_MASK_SRC (flag) ==
TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET (1) :
GPTU_CON_SRC_EXT_SET (0);
else
con_reg |=
TIMER_FLAG_MASK_SRC (flag) ==
TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET (1) :
GPTU_CON_SRC_EG_SET (0);
con_reg |=
TIMER_FLAG_MASK_SYNC (flag) ==
TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET (0) :
GPTU_CON_SYNC_SET (1);
con_reg |=
TIMER_FLAG_MASK_INVERT (flag) ==
TIMER_FLAG_REAL ? GPTU_CON_INV_SET (0) : GPTU_CON_INV_SET (1);
con_reg |=
TIMER_FLAG_MASK_SIZE (flag) ==
TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET (0) :
GPTU_CON_EXT_SET (1);
con_reg |=
TIMER_FLAG_MASK_STOP (flag) ==
TIMER_FLAG_ONCE ? GPTU_CON_STP_SET (1) : GPTU_CON_STP_SET (0);
con_reg |=
TIMER_FLAG_MASK_TYPE (flag) ==
TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET (0) :
GPTU_CON_CNT_SET (1);
con_reg |=
TIMER_FLAG_MASK_DIR (flag) ==
TIMER_FLAG_UP ? GPTU_CON_DIR_SET (1) : GPTU_CON_DIR_SET (0);
/*
* Fill up running data.
*/
timer_dev.timer[timer - FIRST_TIMER].flag = flag;
timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1;
timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2;
if (TIMER_FLAG_MASK_SIZE (flag) != TIMER_FLAG_16BIT)
timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag;
/*
* Enable GPTU module.
*/
if (!timer_dev.f_gptu_on) {
ifxmips_enable_gptu ();
timer_dev.f_gptu_on = 1;
}
/*
* Enable IRQ.
*/
if (TIMER_FLAG_MASK_HANDLE (flag) != TIMER_FLAG_NO_HANDLE) {
if (TIMER_FLAG_MASK_HANDLE (flag) == TIMER_FLAG_SIGNAL)
timer_dev.timer[timer - FIRST_TIMER].arg1 =
(unsigned long) find_task_by_pid ((int) arg1);
irnen_reg = 1 << (timer - FIRST_TIMER);
if (TIMER_FLAG_MASK_HANDLE (flag) == TIMER_FLAG_SIGNAL
|| (TIMER_FLAG_MASK_HANDLE (flag) ==
TIMER_FLAG_CALLBACK_IN_IRQ
&& timer_dev.timer[timer - FIRST_TIMER].arg1)) {
enable_irq (timer_dev.timer[timer - FIRST_TIMER].irq);
timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1;
}
}
else
irnen_reg = 0;
/*
* Write config register, reload value and enable interrupt.
*/
n = timer >> 1;
X = timer & 0x01;
*IFXMIPS_GPTU_CON (n, X) = con_reg;
*IFXMIPS_GPTU_RELOAD (n, X) = value;
// printk("reload value = %d\n", (u32)value);
*IFXMIPS_GPTU_IRNEN |= irnen_reg;
mutex_unlock(&timer_dev.gptu_mutex);
printk("successful!\n");
return ret;
}
int
ifxmips_free_timer(unsigned int timer)
{
unsigned int flag;
unsigned int mask;
int n, X;
if(!timer_dev.f_gptu_on)
return -EINVAL;
if(timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
return -EINVAL;
mutex_lock(&timer_dev.gptu_mutex);
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
if(TIMER_FLAG_MASK_SIZE (flag) != TIMER_FLAG_16BIT)
timer &= ~0x01;
mask = (TIMER_FLAG_MASK_SIZE (flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
if(((timer_dev.occupation & mask) ^ mask))
{
mutex_unlock(&timer_dev.gptu_mutex);
return -EINVAL;
}
n = timer >> 1;
X = timer & 0x01;
if(GPTU_CON_EN (n, X))
*IFXMIPS_GPTU_RUN (n, X) = GPTU_RUN_CEN_SET (1);
*IFXMIPS_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET (n, X, 1);
*IFXMIPS_GPTU_IRNCR |= GPTU_IRNCR_TC_SET (n, X, 1);
if(timer_dev.timer[timer - FIRST_TIMER].f_irq_on) {
disable_irq (timer_dev.timer[timer - FIRST_TIMER].irq);
timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0;
}
timer_dev.occupation &= ~mask;
if(!timer_dev.occupation && timer_dev.f_gptu_on)
{
ifxmips_disable_gptu();
timer_dev.f_gptu_on = 0;
}
mutex_unlock(&timer_dev.gptu_mutex);
return 0;
}
int
ifxmips_start_timer(unsigned int timer, int is_resume)
{
unsigned int flag;
unsigned int mask;
int n, X;
if(!timer_dev.f_gptu_on)
return -EINVAL;
if(timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
return -EINVAL;
mutex_lock(&timer_dev.gptu_mutex);
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
if(TIMER_FLAG_MASK_SIZE (flag) != TIMER_FLAG_16BIT)
timer &= ~0x01;
mask = (TIMER_FLAG_MASK_SIZE (flag) ==
TIMER_FLAG_16BIT ? 1 : 3) << timer;
if(((timer_dev.occupation & mask) ^ mask))
{
mutex_unlock(&timer_dev.gptu_mutex);
return -EINVAL;
}
n = timer >> 1;
X = timer & 0x01;
*IFXMIPS_GPTU_RUN (n, X) = GPTU_RUN_RL_SET (!is_resume) | GPTU_RUN_SEN_SET (1);
mutex_unlock(&timer_dev.gptu_mutex);
return 0;
}
int
ifxmips_stop_timer(unsigned int timer)
{
unsigned int flag;
unsigned int mask;
int n, X;
if (!timer_dev.f_gptu_on)
return -EINVAL;
if (timer < FIRST_TIMER
|| timer >= FIRST_TIMER + timer_dev.number_of_timers)
return -EINVAL;
mutex_lock(&timer_dev.gptu_mutex);
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
if(TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
timer &= ~0x01;
mask = (TIMER_FLAG_MASK_SIZE (flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
if(((timer_dev.occupation & mask) ^ mask))
{
mutex_unlock(&timer_dev.gptu_mutex);
return -EINVAL;
}
n = timer >> 1;
X = timer & 0x01;
*IFXMIPS_GPTU_RUN (n, X) = GPTU_RUN_CEN_SET (1);
mutex_unlock(&timer_dev.gptu_mutex);
return 0;
}
int
ifxmips_reset_counter_flags(u32 timer, u32 flags)
{
unsigned int oflag;
unsigned int mask, con_reg;
int n, X;
if(!timer_dev.f_gptu_on)
return -EINVAL;
if(timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
return -EINVAL;
mutex_lock(&timer_dev.gptu_mutex);
oflag = timer_dev.timer[timer - FIRST_TIMER].flag;
if(TIMER_FLAG_MASK_SIZE (oflag) != TIMER_FLAG_16BIT)
timer &= ~0x01;
mask = (TIMER_FLAG_MASK_SIZE (oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
if(((timer_dev.occupation & mask) ^ mask))
{
mutex_unlock(&timer_dev.gptu_mutex);
return -EINVAL;
}
switch(TIMER_FLAG_MASK_EDGE (flags))
{
default:
case TIMER_FLAG_NONE_EDGE:
con_reg = GPTU_CON_EDGE_SET(0x00);
break;
case TIMER_FLAG_RISE_EDGE:
con_reg = GPTU_CON_EDGE_SET(0x01);
break;
case TIMER_FLAG_FALL_EDGE:
con_reg = GPTU_CON_EDGE_SET(0x02);
break;
case TIMER_FLAG_ANY_EDGE:
con_reg = GPTU_CON_EDGE_SET(0x03);
break;
}
if(TIMER_FLAG_MASK_TYPE (flags) == TIMER_FLAG_TIMER)
con_reg |= TIMER_FLAG_MASK_SRC (flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET (1) : GPTU_CON_SRC_EXT_SET (0);
else
con_reg |= TIMER_FLAG_MASK_SRC (flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET (1) : GPTU_CON_SRC_EG_SET (0);
con_reg |= TIMER_FLAG_MASK_SYNC (flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET (0) : GPTU_CON_SYNC_SET (1);
con_reg |= TIMER_FLAG_MASK_INVERT (flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET (0) : GPTU_CON_INV_SET (1);
con_reg |= TIMER_FLAG_MASK_SIZE (flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET (0) : GPTU_CON_EXT_SET (1);
con_reg |= TIMER_FLAG_MASK_STOP (flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET (1) : GPTU_CON_STP_SET (0);
con_reg |= TIMER_FLAG_MASK_TYPE (flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET (0) : GPTU_CON_CNT_SET (1);
con_reg |= TIMER_FLAG_MASK_DIR (flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET (1) : GPTU_CON_DIR_SET (0);
timer_dev.timer[timer - FIRST_TIMER].flag = flags;
if(TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT)
timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags;
n = timer >> 1;
X = timer & 0x01;
*IFXMIPS_GPTU_CON(n, X) = con_reg;
smp_wmb();
printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *IFXMIPS_GPTU_CON (n, X));
mutex_unlock(&timer_dev.gptu_mutex);
return 0;
}
EXPORT_SYMBOL(ifxmips_reset_counter_flags);
inline int
ifxmips_get_count_value(unsigned int timer, unsigned long *value)
{
unsigned int flag;
unsigned int mask;
int n, X;
if(!timer_dev.f_gptu_on)
return -EINVAL;
if(timer < FIRST_TIMER
|| timer >= FIRST_TIMER + timer_dev.number_of_timers)
return -EINVAL;
mutex_lock(&timer_dev.gptu_mutex);
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
if(TIMER_FLAG_MASK_SIZE (flag) != TIMER_FLAG_16BIT)
timer &= ~0x01;
mask = (TIMER_FLAG_MASK_SIZE (flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
if (((timer_dev.occupation & mask) ^ mask))
{
mutex_unlock(&timer_dev.gptu_mutex);
return -EINVAL;
}
n = timer >> 1;
X = timer & 0x01;
*value = *IFXMIPS_GPTU_COUNT (n, X);
mutex_unlock(&timer_dev.gptu_mutex);
return 0;
}
u32
ifxmips_cal_divider(unsigned long freq)
{
u64 module_freq, fpi = cgu_get_fpi_bus_clock(2);
u32 clock_divider = 1;
module_freq = fpi * 1000;
do_div(module_freq, clock_divider * freq);
return module_freq;
}
int
ifxmips_set_timer (unsigned int timer, unsigned int freq, int is_cyclic,
int is_ext_src, unsigned int handle_flag, unsigned long arg1,
unsigned long arg2)
{
unsigned long divider;
unsigned int flag;
divider = ifxmips_cal_divider(freq);
if (divider == 0)
return -EINVAL;
flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT)
| (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE)
| (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC)
| TIMER_FLAG_TIMER | TIMER_FLAG_DOWN
| TIMER_FLAG_MASK_HANDLE (handle_flag);
printk(KERN_INFO "set_timer(%d, %d), divider = %lu\n", timer, freq, divider);
return ifxmips_request_timer (timer, flag, divider, arg1, arg2);
}
int
ifxmips_set_counter(unsigned int timer, unsigned int flag, u32 reload, unsigned long arg1, unsigned long arg2)
{
printk(KERN_INFO "set_counter(%d, %#x, %d)\n", timer, flag, reload);
return ifxmips_request_timer(timer, flag, reload, arg1, arg2);
}
static int
gptu_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
struct gptu_ioctl_param param;
if (!access_ok (VERIFY_READ, arg, sizeof (struct gptu_ioctl_param)))
return -EFAULT;
copy_from_user (&param, (void *) arg, sizeof (param));
if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER
|| GPTU_SET_COUNTER) && param.timer < 2)
|| cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER)
&& !access_ok (VERIFY_WRITE, arg,
sizeof (struct gptu_ioctl_param)))
return -EFAULT;
switch (cmd) {
case GPTU_REQUEST_TIMER:
ret = ifxmips_request_timer (param.timer, param.flag, param.value,
(unsigned long) param.pid,
(unsigned long) param.sig);
if (ret > 0) {
copy_to_user (&((struct gptu_ioctl_param *) arg)->
timer, &ret, sizeof (&ret));
ret = 0;
}
break;
case GPTU_FREE_TIMER:
ret = ifxmips_free_timer (param.timer);
break;
case GPTU_START_TIMER:
ret = ifxmips_start_timer (param.timer, param.flag);
break;
case GPTU_STOP_TIMER:
ret = ifxmips_stop_timer (param.timer);
break;
case GPTU_GET_COUNT_VALUE:
ret = ifxmips_get_count_value (param.timer, &param.value);
if (!ret)
copy_to_user (&((struct gptu_ioctl_param *) arg)->
value, &param.value,
sizeof (param.value));
break;
case GPTU_CALCULATE_DIVIDER:
param.value = ifxmips_cal_divider (param.value);
if (param.value == 0)
ret = -EINVAL;
else {
copy_to_user (&((struct gptu_ioctl_param *) arg)->
value, &param.value,
sizeof (param.value));
ret = 0;
}
break;
case GPTU_SET_TIMER:
ret = ifxmips_set_timer (param.timer, param.value,
TIMER_FLAG_MASK_STOP (param.flag) !=
TIMER_FLAG_ONCE ? 1 : 0,
TIMER_FLAG_MASK_SRC (param.flag) ==
TIMER_FLAG_EXT_SRC ? 1 : 0,
TIMER_FLAG_MASK_HANDLE (param.flag) ==
TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL :
TIMER_FLAG_NO_HANDLE,
(unsigned long) param.pid,
(unsigned long) param.sig);
if (ret > 0) {
copy_to_user (&((struct gptu_ioctl_param *) arg)->
timer, &ret, sizeof (&ret));
ret = 0;
}
break;
case GPTU_SET_COUNTER:
ifxmips_set_counter (param.timer, param.flag, param.value, 0, 0);
if (ret > 0) {
copy_to_user (&((struct gptu_ioctl_param *) arg)->
timer, &ret, sizeof (&ret));
ret = 0;
}
break;
default:
ret = -ENOTTY;
}
return ret;
}
static int
gptu_open(struct inode *inode, struct file *file)
{
return 0;
}
static int
gptu_release(struct inode *inode, struct file *file)
{
return 0;
}
int __init
ifxmips_gptu_init(void)
{
int ret;
unsigned int i;
ifxmips_w32(0, IFXMIPS_GPTU_IRNEN);
ifxmips_w32(0xfff, IFXMIPS_GPTU_IRNCR);
memset(&timer_dev, 0, sizeof (timer_dev));
mutex_init(&timer_dev.gptu_mutex);
ifxmips_enable_gptu();
timer_dev.number_of_timers = GPTU_ID_CFG * 2;
ifxmips_disable_gptu ();
if(timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2)
timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2;
printk (KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers);
ret = misc_register(&gptu_miscdev);
if(ret)
{
printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret);
return ret;
} else {
printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor);
}
for(i = 0; i < timer_dev.number_of_timers; i++)
{
ret = request_irq (TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]);
if(ret)
{
for (; i >= 0; i--)
free_irq (TIMER_INTERRUPT + i, &timer_dev.timer[i]);
misc_deregister(&gptu_miscdev);
printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret);
return ret;
} else {
timer_dev.timer[i].irq = TIMER_INTERRUPT + i;
disable_irq(timer_dev.timer[i].irq);
printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq);
}
}
return 0;
}
void __exit
ifxmips_gptu_exit (void)
{
unsigned int i;
for(i = 0; i < timer_dev.number_of_timers; i++)
{
if(timer_dev.timer[i].f_irq_on)
disable_irq (timer_dev.timer[i].irq);
free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]);
}
ifxmips_disable_gptu();
misc_deregister(&gptu_miscdev);
}
EXPORT_SYMBOL(ifxmips_request_timer);
EXPORT_SYMBOL(ifxmips_free_timer);
EXPORT_SYMBOL(ifxmips_start_timer);
EXPORT_SYMBOL(ifxmips_stop_timer);
EXPORT_SYMBOL(ifxmips_get_count_value);
EXPORT_SYMBOL(ifxmips_cal_divider);
EXPORT_SYMBOL(ifxmips_set_timer);
EXPORT_SYMBOL(ifxmips_set_counter);
module_init(ifxmips_gptu_init);
module_exit(ifxmips_gptu_exit);

View File

@ -27,6 +27,7 @@
#include <linux/watchdog.h>
#include <linux/miscdevice.h>
#include <asm-mips/ifxmips/ifxmips_wdt.h>
#include <asm-mips/ifxmips/ifxmips_cgu.h>
#include <asm-mips/ifxmips/ifxmips.h>
#define DRVNAME "ifxmips_wdt"
@ -35,7 +36,6 @@
extern unsigned int ifxmips_get_fpi_hz (void);
static int ifxmips_wdt_inuse = 0;
static int ifxmips_wdt_major = 0;
int
ifxmips_wdt_enable (unsigned int timeout)
@ -49,9 +49,7 @@ ifxmips_wdt_enable (unsigned int timeout)
wdt_clkdiv = 1 << (7 * IFXMIPS_BIU_WDT_CR_CLKDIV_GET(ifxmips_r32(IFXMIPS_BIU_WDT_CR)));
wdt_pwl = 0x8000 >> IFXMIPS_BIU_WDT_CR_PWL_GET(ifxmips_r32(IFXMIPS_BIU_WDT_CR));
//TODO
printk("WARNING FUNCTION CALL MISSING!!!");
//ffpi = cgu_get_io_region_clock();
ffpi = cgu_get_io_region_clock();
printk("cpu clock = %d\n", ffpi);
/* caculate reload value */

View File

@ -148,8 +148,21 @@
/*------------ CGU */
#define IFXMIPS_CGU_BASE_ADDR 0xBF103000
#define IFXMIPS_CGU_BASE_ADDR (KSEG1 + 0x1F103000)
#define IFXMIPS_CGU_PLL0_CFG ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0004))
#define IFXMIPS_CGU_PLL1_CFG ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0008))
#define IFXMIPS_CGU_PLL2_CFG ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x000C))
#define IFXMIPS_CGU_SYS ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0010))
#define IFXMIPS_CGU_UPDATE ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0014))
#define IFXMIPS_CGU_IF_CLK ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0018))
#define IFXMIPS_CGU_OSC_CON ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x001C))
#define IFXMIPS_CGU_SMD ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0020))
#define IFXMIPS_CGU_CT1SR ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0028))
#define IFXMIPS_CGU_CT2SR ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x002C))
#define IFXMIPS_CGU_PCMCR ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0030))
#define IFXMIPS_CGU_PCI_CR ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0034))
#define IFXMIPS_CGU_PD_PC ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0038))
#define IFXMIPS_CGU_FMR ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x003C))
/* clock mux */
#define IFXMIPS_CGU_SYS ((u32*)(IFXMIPS_CGU_BASE_ADDR + 0x0010))
@ -179,11 +192,12 @@
#define IFXMIPS_ICU_IM0_ISR ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0000))
#define IFXMIPS_ICU_IM0_IER ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0008))
#define IFXMIPS_ICU_IM0_IOSR ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0010))
#define IFXMIPS_ICU_IM0_IRSR ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0018))
#define IFXMIPS_ICU_IM0_IOSR ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0010))
#define IFXMIPS_ICU_IM0_IRSR ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0018))
#define IFXMIPS_ICU_IM0_IMR ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0020))
#define IFXMIPS_ICU_IM1_ISR ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x0028))
#define IFXMIPS_ICU_IM5_IER ((u32*)(IFXMIPS_ICU_BASE_ADDR + 0x00D0))
#define IFXMIPS_ICU_OFFSET (IFXMIPS_ICU_IM1_ISR - IFXMIPS_ICU_IM0_ISR)
@ -436,5 +450,36 @@
#define IFXMIPS_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
#define IFXMIPS_MPS_CHIPID ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0344))
#define IFXMIPS_MPS_VC0ENR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0000))
#define IFXMIPS_MPS_VC1ENR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0004))
#define IFXMIPS_MPS_VC2ENR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0008))
#define IFXMIPS_MPS_VC3ENR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x000C))
#define IFXMIPS_MPS_RVC0SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0010))
#define IFXMIPS_MPS_RVC1SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0014))
#define IFXMIPS_MPS_RVC2SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0018))
#define IFXMIPS_MPS_RVC3SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x001C))
#define IFXMIPS_MPS_SVC0SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0020))
#define IFXMIPS_MPS_SVC1SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0024))
#define IFXMIPS_MPS_SVC2SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0028))
#define IFXMIPS_MPS_SVC3SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x002C))
#define IFXMIPS_MPS_CVC0SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0030))
#define IFXMIPS_MPS_CVC1SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0034))
#define IFXMIPS_MPS_CVC2SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0038))
#define IFXMIPS_MPS_CVC3SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x003C))
#define IFXMIPS_MPS_RAD0SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0040))
#define IFXMIPS_MPS_RAD1SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0044))
#define IFXMIPS_MPS_SAD0SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0048))
#define IFXMIPS_MPS_SAD1SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x004C))
#define IFXMIPS_MPS_CAD0SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0050))
#define IFXMIPS_MPS_CAD1SR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0054))
#define IFXMIPS_MPS_AD0ENR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x0058))
#define IFXMIPS_MPS_AD1ENR ((u32*)(IFXMIPS_MPS_BASE_ADDR + 0x005C))
#define IFXMIPS_MPS_CHIPID_VERSION_GET(value) (((value) >> 28) & ((1 << 4) - 1))
#define IFXMIPS_MPS_CHIPID_VERSION_SET(value) (((( 1 << 4) - 1) & (value)) << 28)
#define IFXMIPS_MPS_CHIPID_PARTNUM_GET(value) (((value) >> 12) & ((1 << 16) - 1))
#define IFXMIPS_MPS_CHIPID_PARTNUM_SET(value) (((( 1 << 16) - 1) & (value)) << 12)
#define IFXMIPS_MPS_CHIPID_MANID_GET(value) (((value) >> 1) & ((1 << 10) - 1))
#define IFXMIPS_MPS_CHIPID_MANID_SET(value) (((( 1 << 10) - 1) & (value)) << 1)
#endif

View File

@ -0,0 +1,11 @@
#ifndef _IFXMIPS_CGU_H__
#define _IFXMIPS_CGU_H__
u32 cgu_get_mips_clock(int cpu);
u32 cgu_get_cpu_clock(void);
u32 cgu_get_io_region_clock(void);
u32 cgu_get_fpi_bus_clock(int fpi);
u32 cgu_get_pp32_clock(void);
u32 cgu_get_ethernet_clock(int mii);
u32 cgu_get_usb_clock(void);
u32 cgu_get_clockout(int clkout);
#endif

View File

@ -0,0 +1,169 @@
#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
/******************************************************************************
Copyright (c) 2002, Infineon Technologies. All rights reserved.
No Warranty
Because the program is licensed free of charge, there is no warranty for
the program, to the extent permitted by applicable law. Except when
otherwise stated in writing the copyright holders and/or other parties
provide the program "as is" without warranty of any kind, either
expressed or implied, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose. The
entire risk as to the quality and performance of the program is with
you. should the program prove defective, you assume the cost of all
necessary servicing, repair or correction.
In no event unless required by applicable law or agreed to in writing
will any copyright holder, or any other party who may modify and/or
redistribute the program as permitted above, be liable to you for
damages, including any general, special, incidental or consequential
damages arising out of the use or inability to use the program
(including but not limited to loss of data or data being rendered
inaccurate or losses sustained by you or third parties or a failure of
the program to operate with any other programs), even if such holder or
other party has been advised of the possibility of such damages.
******************************************************************************/
/*
* ####################################
* Definition
* ####################################
*/
/*
* Available Timer/Counter Index
*/
#define TIMER(n, X) (n * 2 + (X ? 1 : 0))
#define TIMER_ANY 0x00
#define TIMER1A TIMER(1, 0)
#define TIMER1B TIMER(1, 1)
#define TIMER2A TIMER(2, 0)
#define TIMER2B TIMER(2, 1)
#define TIMER3A TIMER(3, 0)
#define TIMER3B TIMER(3, 1)
/*
* Flag of Timer/Counter
* These flags specify the way in which timer is configured.
*/
/* Bit size of timer/counter. */
#define TIMER_FLAG_16BIT 0x0000
#define TIMER_FLAG_32BIT 0x0001
/* Switch between timer and counter. */
#define TIMER_FLAG_TIMER 0x0000
#define TIMER_FLAG_COUNTER 0x0002
/* Stop or continue when overflowing/underflowing. */
#define TIMER_FLAG_ONCE 0x0000
#define TIMER_FLAG_CYCLIC 0x0004
/* Count up or counter down. */
#define TIMER_FLAG_UP 0x0000
#define TIMER_FLAG_DOWN 0x0008
/* Count on specific level or edge. */
#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000
#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040
#define TIMER_FLAG_RISE_EDGE 0x0010
#define TIMER_FLAG_FALL_EDGE 0x0020
#define TIMER_FLAG_ANY_EDGE 0x0030
/* Signal is syncronous to module clock or not. */
#define TIMER_FLAG_UNSYNC 0x0000
#define TIMER_FLAG_SYNC 0x0080
/* Different interrupt handle type. */
#define TIMER_FLAG_NO_HANDLE 0x0000
#if defined(__KERNEL__)
#define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100
#endif // defined(__KERNEL__)
#define TIMER_FLAG_SIGNAL 0x0300
/* Internal clock source or external clock source */
#define TIMER_FLAG_INT_SRC 0x0000
#define TIMER_FLAG_EXT_SRC 0x1000
/*
* ioctl Command
*/
#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */
#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */
#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */
#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */
#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */
#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/
#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */
#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */
/*
* Data Type Used to Call ioctl
*/
struct gptu_ioctl_param {
unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
* GPTU_SET_COUNTER, this field is ID of expected *
* timer/counter. If it's zero, a timer/counter would *
* be dynamically allocated and ID would be stored in *
* this field. *
* In command GPTU_GET_COUNT_VALUE, this field is *
* ignored. *
* In other command, this field is ID of timer/counter *
* allocated. */
unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
* GPTU_SET_COUNTER, this field contains flags to *
* specify how to configure timer/counter. *
* In command GPTU_START_TIMER, zero indicate start *
* and non-zero indicate resume timer/counter. *
* In other command, this field is ignored. */
unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains *
* init/reload value. *
* In command GPTU_SET_TIMER, this field contains *
* frequency (0.001Hz) of timer. *
* In command GPTU_GET_COUNT_VALUE, current count *
* value would be stored in this field. *
* In command GPTU_CALCULATE_DIVIDER, this field *
* contains frequency wanted, and after calculation, *
* divider would be stored in this field to overwrite *
* the frequency. *
* In other command, this field is ignored. */
int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
* if signal is required, this field contains process *
* ID to which signal would be sent. *
* In other command, this field is ignored. */
int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
* if signal is required, this field contains signal *
* number which would be sent. *
* In other command, this field is ignored. */
};
/*
* ####################################
* Data Type
* ####################################
*/
#if defined(__KERNEL__)
typedef void (*timer_callback)(unsigned long arg);
#endif // defined(__KERNEL__)
/*
* ####################################
* Declaration
* ####################################
*/
#if defined(__KERNEL__)
extern int request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long);
extern int free_timer(unsigned int);
extern int start_timer(unsigned int, int);
extern int stop_timer(unsigned int);
extern int reset_counter_flags(u32 timer, u32 flags);
extern int get_count_value(unsigned int, unsigned long *);
extern u32 cal_divider(unsigned long);
extern int set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long);
extern int set_counter (unsigned int timer, unsigned int flag, u32 reload, unsigned long arg1, unsigned long arg2);
// extern int set_counter(unsigned int, int, int, int, unsigned int, unsigned int, unsigned long, unsigned long);
#endif // defined(__KERNEL__)
#endif // __DANUBE_GPTU_DEV_H__2005_07_26__10_19__