1*71b9114dSArnd Bergmann // SPDX-License-Identifier: GPL-2.0 2*71b9114dSArnd Bergmann // 3*71b9114dSArnd Bergmann // Copyright (c) 2008 Simtec Electronics 4*71b9114dSArnd Bergmann // Ben Dooks <ben@simtec.co.uk> 5*71b9114dSArnd Bergmann // http://armlinux.simtec.co.uk/ 6*71b9114dSArnd Bergmann // 7*71b9114dSArnd Bergmann // S3C series CPU initialisation 8*71b9114dSArnd Bergmann 9*71b9114dSArnd Bergmann /* 10*71b9114dSArnd Bergmann * NOTE: Code in this file is not used on S3C64xx when booting with 11*71b9114dSArnd Bergmann * Device Tree support. 12*71b9114dSArnd Bergmann */ 13*71b9114dSArnd Bergmann 14*71b9114dSArnd Bergmann #include <linux/init.h> 15*71b9114dSArnd Bergmann #include <linux/module.h> 16*71b9114dSArnd Bergmann #include <linux/interrupt.h> 17*71b9114dSArnd Bergmann #include <linux/ioport.h> 18*71b9114dSArnd Bergmann #include <linux/serial_core.h> 19*71b9114dSArnd Bergmann #include <linux/serial_s3c.h> 20*71b9114dSArnd Bergmann #include <linux/platform_device.h> 21*71b9114dSArnd Bergmann #include <linux/of.h> 22*71b9114dSArnd Bergmann 23*71b9114dSArnd Bergmann #include <asm/mach/arch.h> 24*71b9114dSArnd Bergmann #include <asm/mach/map.h> 25*71b9114dSArnd Bergmann 26*71b9114dSArnd Bergmann #include <plat/cpu.h> 27*71b9114dSArnd Bergmann #include <plat/devs.h> 28*71b9114dSArnd Bergmann 29*71b9114dSArnd Bergmann static struct cpu_table *cpu; 30*71b9114dSArnd Bergmann 31*71b9114dSArnd Bergmann static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode, 32*71b9114dSArnd Bergmann struct cpu_table *tab, 33*71b9114dSArnd Bergmann unsigned int count) 34*71b9114dSArnd Bergmann { 35*71b9114dSArnd Bergmann for (; count != 0; count--, tab++) { 36*71b9114dSArnd Bergmann if ((idcode & tab->idmask) == (tab->idcode & tab->idmask)) 37*71b9114dSArnd Bergmann return tab; 38*71b9114dSArnd Bergmann } 39*71b9114dSArnd Bergmann 40*71b9114dSArnd Bergmann return NULL; 41*71b9114dSArnd Bergmann } 42*71b9114dSArnd Bergmann 43*71b9114dSArnd Bergmann void __init s3c_init_cpu(unsigned long idcode, 44*71b9114dSArnd Bergmann struct cpu_table *cputab, unsigned int cputab_size) 45*71b9114dSArnd Bergmann { 46*71b9114dSArnd Bergmann cpu = s3c_lookup_cpu(idcode, cputab, cputab_size); 47*71b9114dSArnd Bergmann 48*71b9114dSArnd Bergmann if (cpu == NULL) { 49*71b9114dSArnd Bergmann printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); 50*71b9114dSArnd Bergmann panic("Unknown S3C24XX CPU"); 51*71b9114dSArnd Bergmann } 52*71b9114dSArnd Bergmann 53*71b9114dSArnd Bergmann printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); 54*71b9114dSArnd Bergmann 55*71b9114dSArnd Bergmann if (cpu->init == NULL) { 56*71b9114dSArnd Bergmann printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); 57*71b9114dSArnd Bergmann panic("Unsupported Samsung CPU"); 58*71b9114dSArnd Bergmann } 59*71b9114dSArnd Bergmann 60*71b9114dSArnd Bergmann if (cpu->map_io) 61*71b9114dSArnd Bergmann cpu->map_io(); 62*71b9114dSArnd Bergmann } 63*71b9114dSArnd Bergmann 64*71b9114dSArnd Bergmann /* s3c24xx_init_clocks 65*71b9114dSArnd Bergmann * 66*71b9114dSArnd Bergmann * Initialise the clock subsystem and associated information from the 67*71b9114dSArnd Bergmann * given master crystal value. 68*71b9114dSArnd Bergmann * 69*71b9114dSArnd Bergmann * xtal = 0 -> use default PLL crystal value (normally 12MHz) 70*71b9114dSArnd Bergmann * != 0 -> PLL crystal value in Hz 71*71b9114dSArnd Bergmann */ 72*71b9114dSArnd Bergmann 73*71b9114dSArnd Bergmann void __init s3c24xx_init_clocks(int xtal) 74*71b9114dSArnd Bergmann { 75*71b9114dSArnd Bergmann if (xtal == 0) 76*71b9114dSArnd Bergmann xtal = 12*1000*1000; 77*71b9114dSArnd Bergmann 78*71b9114dSArnd Bergmann if (cpu == NULL) 79*71b9114dSArnd Bergmann panic("s3c24xx_init_clocks: no cpu setup?\n"); 80*71b9114dSArnd Bergmann 81*71b9114dSArnd Bergmann if (cpu->init_clocks == NULL) 82*71b9114dSArnd Bergmann panic("s3c24xx_init_clocks: cpu has no clock init\n"); 83*71b9114dSArnd Bergmann else 84*71b9114dSArnd Bergmann (cpu->init_clocks)(xtal); 85*71b9114dSArnd Bergmann } 86*71b9114dSArnd Bergmann 87*71b9114dSArnd Bergmann /* uart management */ 88*71b9114dSArnd Bergmann #if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) 89*71b9114dSArnd Bergmann static int nr_uarts __initdata = 0; 90*71b9114dSArnd Bergmann 91*71b9114dSArnd Bergmann #ifdef CONFIG_SERIAL_SAMSUNG_UARTS 92*71b9114dSArnd Bergmann static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS]; 93*71b9114dSArnd Bergmann #endif 94*71b9114dSArnd Bergmann 95*71b9114dSArnd Bergmann /* s3c24xx_init_uartdevs 96*71b9114dSArnd Bergmann * 97*71b9114dSArnd Bergmann * copy the specified platform data and configuration into our central 98*71b9114dSArnd Bergmann * set of devices, before the data is thrown away after the init process. 99*71b9114dSArnd Bergmann * 100*71b9114dSArnd Bergmann * This also fills in the array passed to the serial driver for the 101*71b9114dSArnd Bergmann * early initialisation of the console. 102*71b9114dSArnd Bergmann */ 103*71b9114dSArnd Bergmann 104*71b9114dSArnd Bergmann void __init s3c24xx_init_uartdevs(char *name, 105*71b9114dSArnd Bergmann struct s3c24xx_uart_resources *res, 106*71b9114dSArnd Bergmann struct s3c2410_uartcfg *cfg, int no) 107*71b9114dSArnd Bergmann { 108*71b9114dSArnd Bergmann #ifdef CONFIG_SERIAL_SAMSUNG_UARTS 109*71b9114dSArnd Bergmann struct platform_device *platdev; 110*71b9114dSArnd Bergmann struct s3c2410_uartcfg *cfgptr = uart_cfgs; 111*71b9114dSArnd Bergmann struct s3c24xx_uart_resources *resp; 112*71b9114dSArnd Bergmann int uart; 113*71b9114dSArnd Bergmann 114*71b9114dSArnd Bergmann memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no); 115*71b9114dSArnd Bergmann 116*71b9114dSArnd Bergmann for (uart = 0; uart < no; uart++, cfg++, cfgptr++) { 117*71b9114dSArnd Bergmann platdev = s3c24xx_uart_src[cfgptr->hwport]; 118*71b9114dSArnd Bergmann 119*71b9114dSArnd Bergmann resp = res + cfgptr->hwport; 120*71b9114dSArnd Bergmann 121*71b9114dSArnd Bergmann s3c24xx_uart_devs[uart] = platdev; 122*71b9114dSArnd Bergmann 123*71b9114dSArnd Bergmann platdev->name = name; 124*71b9114dSArnd Bergmann platdev->resource = resp->resources; 125*71b9114dSArnd Bergmann platdev->num_resources = resp->nr_resources; 126*71b9114dSArnd Bergmann 127*71b9114dSArnd Bergmann platdev->dev.platform_data = cfgptr; 128*71b9114dSArnd Bergmann } 129*71b9114dSArnd Bergmann 130*71b9114dSArnd Bergmann nr_uarts = no; 131*71b9114dSArnd Bergmann #endif 132*71b9114dSArnd Bergmann } 133*71b9114dSArnd Bergmann 134*71b9114dSArnd Bergmann void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) 135*71b9114dSArnd Bergmann { 136*71b9114dSArnd Bergmann if (cpu == NULL) 137*71b9114dSArnd Bergmann return; 138*71b9114dSArnd Bergmann 139*71b9114dSArnd Bergmann if (cpu->init_uarts == NULL && IS_ENABLED(CONFIG_SAMSUNG_ATAGS)) { 140*71b9114dSArnd Bergmann printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n"); 141*71b9114dSArnd Bergmann } else 142*71b9114dSArnd Bergmann (cpu->init_uarts)(cfg, no); 143*71b9114dSArnd Bergmann } 144*71b9114dSArnd Bergmann #endif 145*71b9114dSArnd Bergmann 146*71b9114dSArnd Bergmann static int __init s3c_arch_init(void) 147*71b9114dSArnd Bergmann { 148*71b9114dSArnd Bergmann int ret; 149*71b9114dSArnd Bergmann 150*71b9114dSArnd Bergmann /* init is only needed for ATAGS based platforms */ 151*71b9114dSArnd Bergmann if (!IS_ENABLED(CONFIG_ATAGS) || 152*71b9114dSArnd Bergmann (!soc_is_s3c24xx() && !soc_is_s3c64xx())) 153*71b9114dSArnd Bergmann return 0; 154*71b9114dSArnd Bergmann 155*71b9114dSArnd Bergmann // do the correct init for cpu 156*71b9114dSArnd Bergmann 157*71b9114dSArnd Bergmann if (cpu == NULL) { 158*71b9114dSArnd Bergmann /* Not needed when booting with device tree. */ 159*71b9114dSArnd Bergmann if (of_have_populated_dt()) 160*71b9114dSArnd Bergmann return 0; 161*71b9114dSArnd Bergmann panic("s3c_arch_init: NULL cpu\n"); 162*71b9114dSArnd Bergmann } 163*71b9114dSArnd Bergmann 164*71b9114dSArnd Bergmann ret = (cpu->init)(); 165*71b9114dSArnd Bergmann if (ret != 0) 166*71b9114dSArnd Bergmann return ret; 167*71b9114dSArnd Bergmann #if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) 168*71b9114dSArnd Bergmann ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); 169*71b9114dSArnd Bergmann #endif 170*71b9114dSArnd Bergmann return ret; 171*71b9114dSArnd Bergmann } 172*71b9114dSArnd Bergmann 173*71b9114dSArnd Bergmann arch_initcall(s3c_arch_init); 174