1/* linux/arch/arm/plat-s3c24xx/cpu.c 2 * 3 * Copyright (c) 2004-2005 Simtec Electronics 4 * http://www.simtec.co.uk/products/SWLINUX/ 5 * Ben Dooks <ben@simtec.co.uk> 6 * 7 * S3C24XX CPU Support 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22*/ 23 24 25#include <linux/init.h> 26#include <linux/module.h> 27#include <linux/interrupt.h> 28#include <linux/ioport.h> 29#include <linux/serial_core.h> 30#include <linux/platform_device.h> 31#include <linux/delay.h> 32#include <linux/io.h> 33 34#include <mach/hardware.h> 35#include <asm/irq.h> 36#include <asm/cacheflush.h> 37 38#include <asm/mach/arch.h> 39#include <asm/mach/map.h> 40 41#include <mach/system-reset.h> 42 43#include <mach/regs-gpio.h> 44#include <plat/regs-serial.h> 45 46#include <plat/cpu.h> 47#include <plat/devs.h> 48#include <plat/clock.h> 49#include <plat/s3c2400.h> 50#include <plat/s3c2410.h> 51#include <plat/s3c2412.h> 52#include <plat/s3c2416.h> 53#include <plat/s3c244x.h> 54#include <plat/s3c2443.h> 55 56/* table of supported CPUs */ 57 58static const char name_s3c2400[] = "S3C2400"; 59static const char name_s3c2410[] = "S3C2410"; 60static const char name_s3c2412[] = "S3C2412"; 61static const char name_s3c2416[] = "S3C2416/S3C2450"; 62static const char name_s3c2440[] = "S3C2440"; 63static const char name_s3c2442[] = "S3C2442"; 64static const char name_s3c2442b[] = "S3C2442B"; 65static const char name_s3c2443[] = "S3C2443"; 66static const char name_s3c2410a[] = "S3C2410A"; 67static const char name_s3c2440a[] = "S3C2440A"; 68 69static struct cpu_table cpu_ids[] __initdata = { 70 { 71 .idcode = 0x32410000, 72 .idmask = 0xffffffff, 73 .map_io = s3c2410_map_io, 74 .init_clocks = s3c2410_init_clocks, 75 .init_uarts = s3c2410_init_uarts, 76 .init = s3c2410_init, 77 .name = name_s3c2410 78 }, 79 { 80 .idcode = 0x32410002, 81 .idmask = 0xffffffff, 82 .map_io = s3c2410_map_io, 83 .init_clocks = s3c2410_init_clocks, 84 .init_uarts = s3c2410_init_uarts, 85 .init = s3c2410a_init, 86 .name = name_s3c2410a 87 }, 88 { 89 .idcode = 0x32440000, 90 .idmask = 0xffffffff, 91 .map_io = s3c244x_map_io, 92 .init_clocks = s3c244x_init_clocks, 93 .init_uarts = s3c244x_init_uarts, 94 .init = s3c2440_init, 95 .name = name_s3c2440 96 }, 97 { 98 .idcode = 0x32440001, 99 .idmask = 0xffffffff, 100 .map_io = s3c244x_map_io, 101 .init_clocks = s3c244x_init_clocks, 102 .init_uarts = s3c244x_init_uarts, 103 .init = s3c2440_init, 104 .name = name_s3c2440a 105 }, 106 { 107 .idcode = 0x32440aaa, 108 .idmask = 0xffffffff, 109 .map_io = s3c244x_map_io, 110 .init_clocks = s3c244x_init_clocks, 111 .init_uarts = s3c244x_init_uarts, 112 .init = s3c2442_init, 113 .name = name_s3c2442 114 }, 115 { 116 .idcode = 0x32440aab, 117 .idmask = 0xffffffff, 118 .map_io = s3c244x_map_io, 119 .init_clocks = s3c244x_init_clocks, 120 .init_uarts = s3c244x_init_uarts, 121 .init = s3c2442_init, 122 .name = name_s3c2442b 123 }, 124 { 125 .idcode = 0x32412001, 126 .idmask = 0xffffffff, 127 .map_io = s3c2412_map_io, 128 .init_clocks = s3c2412_init_clocks, 129 .init_uarts = s3c2412_init_uarts, 130 .init = s3c2412_init, 131 .name = name_s3c2412, 132 }, 133 { /* a newer version of the s3c2412 */ 134 .idcode = 0x32412003, 135 .idmask = 0xffffffff, 136 .map_io = s3c2412_map_io, 137 .init_clocks = s3c2412_init_clocks, 138 .init_uarts = s3c2412_init_uarts, 139 .init = s3c2412_init, 140 .name = name_s3c2412, 141 }, 142 { /* a strange version of the s3c2416 */ 143 .idcode = 0x32450003, 144 .idmask = 0xffffffff, 145 .map_io = s3c2416_map_io, 146 .init_clocks = s3c2416_init_clocks, 147 .init_uarts = s3c2416_init_uarts, 148 .init = s3c2416_init, 149 .name = name_s3c2416, 150 }, 151 { 152 .idcode = 0x32443001, 153 .idmask = 0xffffffff, 154 .map_io = s3c2443_map_io, 155 .init_clocks = s3c2443_init_clocks, 156 .init_uarts = s3c2443_init_uarts, 157 .init = s3c2443_init, 158 .name = name_s3c2443, 159 }, 160 { 161 .idcode = 0x0, /* S3C2400 doesn't have an idcode */ 162 .idmask = 0xffffffff, 163 .map_io = s3c2400_map_io, 164 .init_clocks = s3c2400_init_clocks, 165 .init_uarts = s3c2400_init_uarts, 166 .init = s3c2400_init, 167 .name = name_s3c2400 168 }, 169}; 170 171/* minimal IO mapping */ 172 173static struct map_desc s3c_iodesc[] __initdata = { 174 IODESC_ENT(GPIO), 175 IODESC_ENT(IRQ), 176 IODESC_ENT(MEMCTRL), 177 IODESC_ENT(UART) 178}; 179 180/* read cpu identificaiton code */ 181 182static unsigned long s3c24xx_read_idcode_v5(void) 183{ 184#if defined(CONFIG_CPU_S3C2416) 185 /* s3c2416 is v5, with S3C24XX_GSTATUS1 instead of S3C2412_GSTATUS1 */ 186 187 u32 gs = __raw_readl(S3C24XX_GSTATUS1); 188 189 /* test for s3c2416 or similar device */ 190 if ((gs >> 16) == 0x3245) 191 return gs; 192#endif 193 194#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) 195 return __raw_readl(S3C2412_GSTATUS1); 196#else 197 return 1UL; /* don't look like an 2400 */ 198#endif 199} 200 201static unsigned long s3c24xx_read_idcode_v4(void) 202{ 203#ifndef CONFIG_CPU_S3C2400 204 return __raw_readl(S3C2410_GSTATUS1); 205#else 206 return 0UL; 207#endif 208} 209 210/* Hook for arm_pm_restart to ensure we execute the reset code 211 * with the caches enabled. It seems at least the S3C2440 has a problem 212 * resetting if there is bus activity interrupted by the reset. 213 */ 214static void s3c24xx_pm_restart(char mode, const char *cmd) 215{ 216 if (mode != 's') { 217 unsigned long flags; 218 219 local_irq_save(flags); 220 __cpuc_flush_kern_all(); 221 __cpuc_flush_user_all(); 222 223 arch_reset(mode, cmd); 224 local_irq_restore(flags); 225 } 226 227 /* fallback, or unhandled */ 228 arm_machine_restart(mode, cmd); 229} 230 231void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) 232{ 233 unsigned long idcode = 0x0; 234 235 /* initialise the io descriptors we need for initialisation */ 236 iotable_init(mach_desc, size); 237 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); 238 239 if (cpu_architecture() >= CPU_ARCH_ARMv5) { 240 idcode = s3c24xx_read_idcode_v5(); 241 } else { 242 idcode = s3c24xx_read_idcode_v4(); 243 } 244 245 arm_pm_restart = s3c24xx_pm_restart; 246 247 s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids)); 248} 249