voron

experimental ARM OS
git clone git://git.2f30.org/voron
Log | Files | Refs | README | LICENSE

dmtimer.c (5515B)


      1 #include <kernel.h>
      2 #include <irq.h>
      3 #include <dmtimer.h>
      4 
      5 #define DMT_OVF_ENA_FLAG		(1<<1)
      6 #define DMT_TCLR_ST			(1<<0)
      7 #define DMT_TCLR_AR			(1<<1)
      8 
      9 #define DMT_1MS_TIOCP_SOFTRESET	(1<<1)
     10 #define DMT_1MS_TIOCP_SMARTIDLE	(2<<3)
     11 #define DMT_1MS_TISTAT_RESETDONE	(1<<0)
     12 
     13 /* gptimer1, gptimer2, gptimer10 */
     14 struct dm_gpt_1ms {
     15 	u32 tidr;
     16 	u32 _pad1[3];
     17 	u32 tiocp_1ms_cfg;
     18 	u32 tistat;
     19 	u32 tisr;
     20 	u32 tier;
     21 	u32 twer;
     22 	u32 tclr;
     23 	u32 tcrr;
     24 	u32 tldr;
     25 	u32 ttgr;
     26 	u32 twps;
     27 	u32 tmar;
     28 	u32 tcar1;
     29 	u32 tsicr;
     30 	u32 tcar2;
     31 	u32 tpir;
     32 	u32 tnir;
     33 	u32 tcvr;
     34 	u32 tocr;
     35 	u32 towr;
     36 };
     37 
     38 #define DMT_TIOCP_SOFTRESET	(1<<0)
     39 #define DMT_TIOCP_SMARTIDLE	(2<<2)
     40 
     41 /* gptimer3, gptimer4, gptimer5, gptimer6
     42  * gptimer7, gptimer8, gptimer9, gptimer11
     43  */
     44 struct dm_gpt {
     45 	u32 tidr;
     46 	u32 _pad1[3];
     47 	u32 tiocp_cfg;
     48 	u32 _pad2[4];
     49 	u32 irqstatus_raw;
     50 	u32 irqstatus;
     51 	u32 irqenable_set;
     52 	u32 irqenable_clr;
     53 	u32 irqwakeen;
     54 	u32 tclr;
     55 	u32 tcrr;
     56 	u32 tldr;
     57 	u32 ttgr;
     58 	u32 twps;
     59 	u32 tmar;
     60 	u32 tcar1;
     61 	u32 tsicr;
     62 	u32 tcar2;
     63 };
     64 
     65 #define DMT_1MS	(1<<0)
     66 #define CM2_CLKSEL	(1<<24)
     67 
     68 struct dmtimer {
     69 	u32 flags;
     70 	dmtimer_callback_func callback_func;
     71 	union {
     72 		u32 *mem;
     73 		struct dm_gpt_1ms *dmt_1ms;
     74 		struct dm_gpt *dmt;
     75 	};
     76 	/* L4PER CM2 register */
     77 	u32 *cm2r;
     78 } dmtimers[] = {
     79 	{ DMT_1MS, NULL, { .mem = (u32*)0x4a318000 }, NULL },		  /* GPTIMER1 */
     80 	{ DMT_1MS, NULL, { .mem = (u32*)0x48032000 }, (u32*)0x4a009438 }, /* GPTIMER2 */
     81 	{	0, NULL, { .mem = (u32*)0x48034000 }, (u32*)0x4a009440 }, /* GPTIMER3 */
     82 	{ 	0, NULL, { .mem = (u32*)0x48036000 }, (u32*)0x4a009448 }, /* GPTIMER4 */
     83 
     84 	/* GPTIMER 5 - 8 are not implemented yet */
     85 	{ 	0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER5 */
     86 	{ 	0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER6 */
     87 	{ 	0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER7 */
     88 	{ 	0, NULL, { .mem = (u32*)NULL }, NULL }, /* GPTIMER8 */
     89 
     90 	{ 	0, NULL, { .mem = (u32*)0x4803e000 }, (u32*)0x4a009450 }, /* GPTIMER9 */
     91 	{ DMT_1MS, NULL, { .mem = (u32*)0x48086000 }, (u32*)0x4a009428 }, /* GPTIMER10 */
     92 	{ 	0, NULL, { .mem = (u32*)0x48088000 }, (u32*)0x4a009430 }  /* GPTIMER11 */
     93 };
     94 
     95 static void
     96 dmtimer_irq_callback(u32 irq_num, struct regs *regs)
     97 {
     98 	u32 val;
     99 	int id, idx;
    100 
    101 	if (irq_num < HW_IRQ(37) || irq_num > HW_IRQ(47))
    102 		return;
    103 
    104 	idx = irq_num - HW_IRQ(37);
    105 	id = idx + 1;
    106 
    107 	if (dmtimers[idx].mem == NULL)
    108 		return;
    109 
    110 	/* read type of event */
    111 	if (dmtimers[idx].flags & DMT_1MS)
    112 		val = readl(&dmtimers[idx].dmt_1ms->tisr);
    113 	else
    114 		val = readl(&dmtimers[idx].dmt->irqstatus);
    115 
    116 	if (dmtimers[idx].callback_func)
    117 		dmtimers[idx].callback_func(id, regs);
    118 
    119 	/* clear event by writing 1 to the bits */
    120 	if (dmtimers[idx].flags & DMT_1MS)
    121 		writel(val, &dmtimers[idx].dmt_1ms->tisr);
    122 	else
    123 		writel(val, &dmtimers[idx].dmt->irqstatus);
    124 }
    125 
    126 static int
    127 reset_timer(int id)
    128 {
    129 	u32 val;
    130 	int idx;
    131 
    132 	if (id <= 0 || id > 11)
    133 		return -EINVAL;
    134 
    135 	idx = id - 1;
    136 
    137 	/* not implemented yet */
    138 	if (dmtimers[idx].mem == NULL)
    139 		return -ENOSYS;
    140 
    141 	if (dmtimers[idx].flags & DMT_1MS) {
    142 		/* request reset */
    143 		writel(DMT_1MS_TIOCP_SOFTRESET, &dmtimers[idx].dmt_1ms->tiocp_1ms_cfg);
    144 		/* wait until reset is done */
    145 		while (!(readl(&dmtimers[idx].dmt_1ms->tistat) & DMT_1MS_TISTAT_RESETDONE))
    146 			;
    147 	} else {
    148 		/* request reset */
    149 		writel(DMT_TIOCP_SOFTRESET, &dmtimers[idx].dmt->tiocp_cfg);
    150 		/* wait until reset is done */
    151 		while (readl(&dmtimers[idx].dmt->tiocp_cfg) & DMT_TIOCP_SOFTRESET)
    152 			;
    153 	}
    154 
    155 	/* enable 32KHz clock */
    156 	if (dmtimers[idx].cm2r) {
    157 		val = readl(dmtimers[idx].cm2r);
    158 		val |= CM2_CLKSEL;
    159 		writel(val, dmtimers[idx].cm2r);
    160 	}
    161 
    162 	return 0;
    163 }
    164 
    165 int
    166 dmtimer_trigger(int id)
    167 {
    168 	int idx;
    169 
    170 	if (id <= 0 || id > 11)
    171 		return -EINVAL;
    172 
    173 	idx = id - 1;
    174 
    175 	/* not implemented yet */
    176 	if (dmtimers[idx].mem == NULL)
    177 		return -ENOSYS;
    178 
    179 	/* manually overflow the timer */
    180 	if (dmtimers[idx].flags & DMT_1MS)
    181 		writel(0xffffffff, &dmtimers[idx].dmt_1ms->tcrr);
    182 	else
    183 		writel(0xffffffff, &dmtimers[idx].dmt->tcrr);
    184 
    185 	return 0;
    186 }
    187 
    188 int
    189 dmtimer_register(int id, dmtimer_callback_func func, u32 ms)
    190 {
    191 	int ret, idx;
    192 	u32 val;
    193 
    194 	if (id <= 0 || id > 11 || ms == 0 || func == NULL)
    195 		return -EINVAL;
    196 
    197 	idx = id - 1;
    198 
    199 	/* not implemented yet */
    200 	if (dmtimers[idx].mem == NULL)
    201 		return -ENOSYS;
    202 
    203 	ret = reset_timer(id);
    204 	if (ret)
    205 		return ret;
    206 
    207 	ret = irq_register(HW_IRQ(37) + idx, dmtimer_irq_callback);
    208 	if (ret)
    209 		return ret;
    210 	dmtimers[idx].callback_func = func;
    211 
    212 	if (dmtimers[idx].flags & DMT_1MS) {
    213 		/* enable start-idle */
    214 		writel(DMT_1MS_TIOCP_SMARTIDLE, &dmtimers[idx].dmt_1ms->tiocp_1ms_cfg);
    215 
    216 		/* set milliseconds */
    217 		val = 0xffffffff;
    218 		val -= ms * 32;
    219 		writel(val, &dmtimers[idx].dmt_1ms->tldr);
    220 
    221 		/* writing to TTGR causes TCRR to be loaded from TLDR */
    222 		writel(1, &dmtimers[idx].dmt_1ms->ttgr);
    223 		/* enable overflow interrupt */
    224 		writel(DMT_OVF_ENA_FLAG, &dmtimers[idx].dmt_1ms->tier);
    225 		/* start timer and enable autoreload */
    226 		writel(DMT_TCLR_ST | DMT_TCLR_AR, &dmtimers[idx].dmt_1ms->tclr);
    227 	} else {
    228 		/* enable start-idle */
    229 		writel(DMT_TIOCP_SMARTIDLE, &dmtimers[idx].dmt->tiocp_cfg);
    230 
    231 		/* set milliseconds */
    232 		val = 0xffffffff;
    233 		val -= ms * 32;
    234 		writel(val, &dmtimers[idx].dmt->tldr);
    235 
    236 		/* writing to TTGR causes TCRR to be loaded from TLDR */
    237 		writel(1, &dmtimers[idx].dmt->ttgr);
    238 		/* enable overflow interrupt */
    239 		writel(DMT_OVF_ENA_FLAG, &dmtimers[idx].dmt->irqenable_set);
    240 		/* start timer and enable autoreload */
    241 		writel(DMT_TCLR_ST | DMT_TCLR_AR, &dmtimers[idx].dmt->tclr);
    242 	}
    243 
    244 	return 0;
    245 }
    246 
    247 void
    248 dmtimer_init(void)
    249 {
    250 	int i;
    251 	for (i = 1; i <= 11; i++)
    252 		reset_timer(i);
    253 }