1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * linux/arch/arm/mach-ebsa110/core.c 4 * 5 * Copyright (C) 1998-2001 Russell King 6 * 7 * Extra MM routines for the EBSA-110 architecture 8 */ 9#include <linux/kernel.h> 10#include <linux/mm.h> 11#include <linux/interrupt.h> 12#include <linux/serial_8250.h> 13#include <linux/init.h> 14#include <linux/io.h> 15 16#include <mach/hardware.h> 17#include <asm/irq.h> 18#include <asm/setup.h> 19#include <asm/mach-types.h> 20#include <asm/page.h> 21#include <asm/system_misc.h> 22 23#include <asm/mach/arch.h> 24#include <asm/mach/irq.h> 25#include <asm/mach/map.h> 26 27#include <asm/mach/time.h> 28 29#include "core.h" 30 31static void ebsa110_mask_irq(struct irq_data *d) 32{ 33 __raw_writeb(1 << d->irq, IRQ_MCLR); 34} 35 36static void ebsa110_unmask_irq(struct irq_data *d) 37{ 38 __raw_writeb(1 << d->irq, IRQ_MSET); 39} 40 41static struct irq_chip ebsa110_irq_chip = { 42 .irq_ack = ebsa110_mask_irq, 43 .irq_mask = ebsa110_mask_irq, 44 .irq_unmask = ebsa110_unmask_irq, 45}; 46 47static void __init ebsa110_init_irq(void) 48{ 49 unsigned long flags; 50 unsigned int irq; 51 52 local_irq_save(flags); 53 __raw_writeb(0xff, IRQ_MCLR); 54 __raw_writeb(0x55, IRQ_MSET); 55 __raw_writeb(0x00, IRQ_MSET); 56 if (__raw_readb(IRQ_MASK) != 0x55) 57 while (1); 58 __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */ 59 local_irq_restore(flags); 60 61 for (irq = 0; irq < NR_IRQS; irq++) { 62 irq_set_chip_and_handler(irq, &ebsa110_irq_chip, 63 handle_level_irq); 64 irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); 65 } 66} 67 68static struct map_desc ebsa110_io_desc[] __initdata = { 69 /* 70 * sparse external-decode ISAIO space 71 */ 72 { /* IRQ_STAT/IRQ_MCLR */ 73 .virtual = (unsigned long)IRQ_STAT, 74 .pfn = __phys_to_pfn(TRICK4_PHYS), 75 .length = TRICK4_SIZE, 76 .type = MT_DEVICE 77 }, { /* IRQ_MASK/IRQ_MSET */ 78 .virtual = (unsigned long)IRQ_MASK, 79 .pfn = __phys_to_pfn(TRICK3_PHYS), 80 .length = TRICK3_SIZE, 81 .type = MT_DEVICE 82 }, { /* SOFT_BASE */ 83 .virtual = (unsigned long)SOFT_BASE, 84 .pfn = __phys_to_pfn(TRICK1_PHYS), 85 .length = TRICK1_SIZE, 86 .type = MT_DEVICE 87 }, { /* PIT_BASE */ 88 .virtual = (unsigned long)PIT_BASE, 89 .pfn = __phys_to_pfn(TRICK0_PHYS), 90 .length = TRICK0_SIZE, 91 .type = MT_DEVICE 92 }, 93 94 /* 95 * self-decode ISAIO space 96 */ 97 { 98 .virtual = ISAIO_BASE, 99 .pfn = __phys_to_pfn(ISAIO_PHYS), 100 .length = ISAIO_SIZE, 101 .type = MT_DEVICE 102 }, { 103 .virtual = ISAMEM_BASE, 104 .pfn = __phys_to_pfn(ISAMEM_PHYS), 105 .length = ISAMEM_SIZE, 106 .type = MT_DEVICE 107 } 108}; 109 110static void __init ebsa110_map_io(void) 111{ 112 iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc)); 113} 114 115static void __iomem *ebsa110_ioremap_caller(phys_addr_t cookie, size_t size, 116 unsigned int flags, void *caller) 117{ 118 return (void __iomem *)cookie; 119} 120 121static void ebsa110_iounmap(volatile void __iomem *io_addr) 122{} 123 124static void __init ebsa110_init_early(void) 125{ 126 arch_ioremap_caller = ebsa110_ioremap_caller; 127 arch_iounmap = ebsa110_iounmap; 128} 129 130#define PIT_CTRL (PIT_BASE + 0x0d) 131#define PIT_T2 (PIT_BASE + 0x09) 132#define PIT_T1 (PIT_BASE + 0x05) 133#define PIT_T0 (PIT_BASE + 0x01) 134 135/* 136 * This is the rate at which your MCLK signal toggles (in Hz) 137 * This was measured on a 10 digit frequency counter sampling 138 * over 1 second. 139 */ 140#define MCLK 47894000 141 142/* 143 * This is the rate at which the PIT timers get clocked 144 */ 145#define CLKBY7 (MCLK / 7) 146 147/* 148 * This is the counter value. We tick at 200Hz on this platform. 149 */ 150#define COUNT ((CLKBY7 + (HZ / 2)) / HZ) 151 152/* 153 * Get the time offset from the system PIT. Note that if we have missed an 154 * interrupt, then the PIT counter will roll over (ie, be negative). 155 * This actually works out to be convenient. 156 */ 157static u32 ebsa110_gettimeoffset(void) 158{ 159 unsigned long offset, count; 160 161 __raw_writeb(0x40, PIT_CTRL); 162 count = __raw_readb(PIT_T1); 163 count |= __raw_readb(PIT_T1) << 8; 164 165 /* 166 * If count > COUNT, make the number negative. 167 */ 168 if (count > COUNT) 169 count |= 0xffff0000; 170 171 offset = COUNT; 172 offset -= count; 173 174 /* 175 * `offset' is in units of timer counts. Convert 176 * offset to units of microseconds. 177 */ 178 offset = offset * (1000000 / HZ) / COUNT; 179 180 return offset * 1000; 181} 182 183static irqreturn_t 184ebsa110_timer_interrupt(int irq, void *dev_id) 185{ 186 u32 count; 187 188 /* latch and read timer 1 */ 189 __raw_writeb(0x40, PIT_CTRL); 190 count = __raw_readb(PIT_T1); 191 count |= __raw_readb(PIT_T1) << 8; 192 193 count += COUNT; 194 195 __raw_writeb(count & 0xff, PIT_T1); 196 __raw_writeb(count >> 8, PIT_T1); 197 198 timer_tick(); 199 200 return IRQ_HANDLED; 201} 202 203/* 204 * Set up timer interrupt. 205 */ 206void __init ebsa110_timer_init(void) 207{ 208 int irq = IRQ_EBSA110_TIMER0; 209 210 arch_gettimeoffset = ebsa110_gettimeoffset; 211 212 /* 213 * Timer 1, mode 2, LSB/MSB 214 */ 215 __raw_writeb(0x70, PIT_CTRL); 216 __raw_writeb(COUNT & 0xff, PIT_T1); 217 __raw_writeb(COUNT >> 8, PIT_T1); 218 219 if (request_irq(irq, ebsa110_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 220 "EBSA110 Timer Tick", NULL)) 221 pr_err("Failed to request irq %d (EBSA110 Timer Tick)\n", irq); 222} 223 224static struct plat_serial8250_port serial_platform_data[] = { 225 { 226 .iobase = 0x3f8, 227 .irq = 1, 228 .uartclk = 1843200, 229 .regshift = 0, 230 .iotype = UPIO_PORT, 231 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 232 }, 233 { 234 .iobase = 0x2f8, 235 .irq = 2, 236 .uartclk = 1843200, 237 .regshift = 0, 238 .iotype = UPIO_PORT, 239 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 240 }, 241 { }, 242}; 243 244static struct platform_device serial_device = { 245 .name = "serial8250", 246 .id = PLAT8250_DEV_PLATFORM, 247 .dev = { 248 .platform_data = serial_platform_data, 249 }, 250}; 251 252static struct resource am79c961_resources[] = { 253 { 254 .start = 0x220, 255 .end = 0x238, 256 .flags = IORESOURCE_IO, 257 }, { 258 .start = IRQ_EBSA110_ETHERNET, 259 .end = IRQ_EBSA110_ETHERNET, 260 .flags = IORESOURCE_IRQ, 261 }, 262}; 263 264static struct platform_device am79c961_device = { 265 .name = "am79c961", 266 .id = -1, 267 .num_resources = ARRAY_SIZE(am79c961_resources), 268 .resource = am79c961_resources, 269}; 270 271static struct platform_device *ebsa110_devices[] = { 272 &serial_device, 273 &am79c961_device, 274}; 275 276/* 277 * EBSA110 idling methodology: 278 * 279 * We can not execute the "wait for interrupt" instruction since that 280 * will stop our MCLK signal (which provides the clock for the glue 281 * logic, and therefore the timer interrupt). 282 * 283 * Instead, we spin, polling the IRQ_STAT register for the occurrence 284 * of any interrupt with core clock down to the memory clock. 285 */ 286static void ebsa110_idle(void) 287{ 288 const char *irq_stat = (char *)0xff000000; 289 290 /* disable clock switching */ 291 asm volatile ("mcr p15, 0, ip, c15, c2, 2" : : : "cc"); 292 293 /* wait for an interrupt to occur */ 294 while (!*irq_stat); 295 296 /* enable clock switching */ 297 asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc"); 298} 299 300static int __init ebsa110_init(void) 301{ 302 arm_pm_idle = ebsa110_idle; 303 return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices)); 304} 305 306arch_initcall(ebsa110_init); 307 308static void ebsa110_restart(enum reboot_mode mode, const char *cmd) 309{ 310 soft_restart(0x80000000); 311} 312 313MACHINE_START(EBSA110, "EBSA110") 314 /* Maintainer: Russell King */ 315 .atag_offset = 0x400, 316 .reserve_lp0 = 1, 317 .reserve_lp2 = 1, 318 .map_io = ebsa110_map_io, 319 .init_early = ebsa110_init_early, 320 .init_irq = ebsa110_init_irq, 321 .init_time = ebsa110_timer_init, 322 .restart = ebsa110_restart, 323MACHINE_END 324