common.c revision 3a083227a45cbbf5d29e6fe7c093af9e09905d4d
1/* 2 * linux/arch/arm/mach-clps711x/core.c 3 * 4 * Core support for the CLPS711x-based machines. 5 * 6 * Copyright (C) 2001,2011 Deep Blue Solutions Ltd 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22#include <linux/kernel.h> 23#include <linux/mm.h> 24#include <linux/init.h> 25#include <linux/interrupt.h> 26#include <linux/io.h> 27#include <linux/irq.h> 28#include <linux/sched.h> 29#include <linux/timex.h> 30 31#include <asm/sizes.h> 32#include <mach/hardware.h> 33#include <asm/irq.h> 34#include <asm/leds.h> 35#include <asm/pgtable.h> 36#include <asm/page.h> 37#include <asm/mach/map.h> 38#include <asm/mach/time.h> 39#include <asm/hardware/clps7111.h> 40 41/* 42 * This maps the generic CLPS711x registers 43 */ 44static struct map_desc clps711x_io_desc[] __initdata = { 45 { 46 .virtual = CLPS7111_VIRT_BASE, 47 .pfn = __phys_to_pfn(CLPS7111_PHYS_BASE), 48 .length = SZ_1M, 49 .type = MT_DEVICE 50 } 51}; 52 53void __init clps711x_map_io(void) 54{ 55 iotable_init(clps711x_io_desc, ARRAY_SIZE(clps711x_io_desc)); 56} 57 58static void int1_mask(struct irq_data *d) 59{ 60 u32 intmr1; 61 62 intmr1 = clps_readl(INTMR1); 63 intmr1 &= ~(1 << d->irq); 64 clps_writel(intmr1, INTMR1); 65} 66 67static void int1_ack(struct irq_data *d) 68{ 69 u32 intmr1; 70 71 intmr1 = clps_readl(INTMR1); 72 intmr1 &= ~(1 << d->irq); 73 clps_writel(intmr1, INTMR1); 74 75 switch (d->irq) { 76 case IRQ_CSINT: clps_writel(0, COEOI); break; 77 case IRQ_TC1OI: clps_writel(0, TC1EOI); break; 78 case IRQ_TC2OI: clps_writel(0, TC2EOI); break; 79 case IRQ_RTCMI: clps_writel(0, RTCEOI); break; 80 case IRQ_TINT: clps_writel(0, TEOI); break; 81 case IRQ_UMSINT: clps_writel(0, UMSEOI); break; 82 } 83} 84 85static void int1_unmask(struct irq_data *d) 86{ 87 u32 intmr1; 88 89 intmr1 = clps_readl(INTMR1); 90 intmr1 |= 1 << d->irq; 91 clps_writel(intmr1, INTMR1); 92} 93 94static struct irq_chip int1_chip = { 95 .irq_ack = int1_ack, 96 .irq_mask = int1_mask, 97 .irq_unmask = int1_unmask, 98}; 99 100static void int2_mask(struct irq_data *d) 101{ 102 u32 intmr2; 103 104 intmr2 = clps_readl(INTMR2); 105 intmr2 &= ~(1 << (d->irq - 16)); 106 clps_writel(intmr2, INTMR2); 107} 108 109static void int2_ack(struct irq_data *d) 110{ 111 u32 intmr2; 112 113 intmr2 = clps_readl(INTMR2); 114 intmr2 &= ~(1 << (d->irq - 16)); 115 clps_writel(intmr2, INTMR2); 116 117 switch (d->irq) { 118 case IRQ_KBDINT: clps_writel(0, KBDEOI); break; 119 } 120} 121 122static void int2_unmask(struct irq_data *d) 123{ 124 u32 intmr2; 125 126 intmr2 = clps_readl(INTMR2); 127 intmr2 |= 1 << (d->irq - 16); 128 clps_writel(intmr2, INTMR2); 129} 130 131static struct irq_chip int2_chip = { 132 .irq_ack = int2_ack, 133 .irq_mask = int2_mask, 134 .irq_unmask = int2_unmask, 135}; 136 137void __init clps711x_init_irq(void) 138{ 139 unsigned int i; 140 141 for (i = 0; i < NR_IRQS; i++) { 142 if (INT1_IRQS & (1 << i)) { 143 irq_set_chip_and_handler(i, &int1_chip, 144 handle_level_irq); 145 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 146 } 147 if (INT2_IRQS & (1 << i)) { 148 irq_set_chip_and_handler(i, &int2_chip, 149 handle_level_irq); 150 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 151 } 152 } 153 154 /* 155 * Disable interrupts 156 */ 157 clps_writel(0, INTMR1); 158 clps_writel(0, INTMR2); 159 160 /* 161 * Clear down any pending interrupts 162 */ 163 clps_writel(0, COEOI); 164 clps_writel(0, TC1EOI); 165 clps_writel(0, TC2EOI); 166 clps_writel(0, RTCEOI); 167 clps_writel(0, TEOI); 168 clps_writel(0, UMSEOI); 169 clps_writel(0, SYNCIO); 170 clps_writel(0, KBDEOI); 171} 172 173/* 174 * gettimeoffset() returns time since last timer tick, in usecs. 175 * 176 * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. 177 * 'tick' is usecs per jiffy. 178 */ 179static unsigned long clps711x_gettimeoffset(void) 180{ 181 unsigned long hwticks; 182 hwticks = LATCH - (clps_readl(TC2D) & 0xffff); /* since last underflow */ 183 return (hwticks * (tick_nsec / 1000)) / LATCH; 184} 185 186/* 187 * IRQ handler for the timer 188 */ 189static irqreturn_t p720t_timer_interrupt(int irq, void *dev_id) 190{ 191 timer_tick(); 192 return IRQ_HANDLED; 193} 194 195static struct irqaction clps711x_timer_irq = { 196 .name = "CLPS711x Timer Tick", 197 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 198 .handler = p720t_timer_interrupt, 199}; 200 201static void __init clps711x_timer_init(void) 202{ 203 struct timespec tv; 204 unsigned int syscon; 205 206 syscon = clps_readl(SYSCON1); 207 syscon |= SYSCON1_TC2S | SYSCON1_TC2M; 208 clps_writel(syscon, SYSCON1); 209 210 clps_writel(LATCH-1, TC2D); /* 512kHz / 100Hz - 1 */ 211 212 setup_irq(IRQ_TC2OI, &clps711x_timer_irq); 213 214 tv.tv_nsec = 0; 215 tv.tv_sec = clps_readl(RTCDR); 216 do_settimeofday(&tv); 217} 218 219struct sys_timer clps711x_timer = { 220 .init = clps711x_timer_init, 221 .offset = clps711x_gettimeoffset, 222}; 223