171b9114dSArnd Bergmann // SPDX-License-Identifier: GPL-2.0 271b9114dSArnd Bergmann // 371b9114dSArnd Bergmann // Copyright (c) 2008 Simtec Electronics 471b9114dSArnd Bergmann // Ben Dooks <ben@simtec.co.uk> 571b9114dSArnd Bergmann // http://armlinux.simtec.co.uk/ 671b9114dSArnd Bergmann // 771b9114dSArnd Bergmann // S3C series CPU initialisation 871b9114dSArnd Bergmann 971b9114dSArnd Bergmann /* 1071b9114dSArnd Bergmann * NOTE: Code in this file is not used on S3C64xx when booting with 1171b9114dSArnd Bergmann * Device Tree support. 1271b9114dSArnd Bergmann */ 1371b9114dSArnd Bergmann 1471b9114dSArnd Bergmann #include <linux/init.h> 1571b9114dSArnd Bergmann #include <linux/module.h> 1671b9114dSArnd Bergmann #include <linux/interrupt.h> 1771b9114dSArnd Bergmann #include <linux/ioport.h> 1871b9114dSArnd Bergmann #include <linux/serial_core.h> 1971b9114dSArnd Bergmann #include <linux/serial_s3c.h> 2071b9114dSArnd Bergmann #include <linux/platform_device.h> 2171b9114dSArnd Bergmann #include <linux/of.h> 2271b9114dSArnd Bergmann 2371b9114dSArnd Bergmann #include <asm/mach/arch.h> 2471b9114dSArnd Bergmann #include <asm/mach/map.h> 2571b9114dSArnd Bergmann 26*c6ff132dSArnd Bergmann #include "cpu.h" 27*c6ff132dSArnd Bergmann #include "devs.h" 2871b9114dSArnd Bergmann 2971b9114dSArnd Bergmann static struct cpu_table *cpu; 3071b9114dSArnd Bergmann 3171b9114dSArnd Bergmann static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode, 3271b9114dSArnd Bergmann struct cpu_table *tab, 3371b9114dSArnd Bergmann unsigned int count) 3471b9114dSArnd Bergmann { 3571b9114dSArnd Bergmann for (; count != 0; count--, tab++) { 3671b9114dSArnd Bergmann if ((idcode & tab->idmask) == (tab->idcode & tab->idmask)) 3771b9114dSArnd Bergmann return tab; 3871b9114dSArnd Bergmann } 3971b9114dSArnd Bergmann 4071b9114dSArnd Bergmann return NULL; 4171b9114dSArnd Bergmann } 4271b9114dSArnd Bergmann 4371b9114dSArnd Bergmann void __init s3c_init_cpu(unsigned long idcode, 4471b9114dSArnd Bergmann struct cpu_table *cputab, unsigned int cputab_size) 4571b9114dSArnd Bergmann { 4671b9114dSArnd Bergmann cpu = s3c_lookup_cpu(idcode, cputab, cputab_size); 4771b9114dSArnd Bergmann 4871b9114dSArnd Bergmann if (cpu == NULL) { 4971b9114dSArnd Bergmann printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); 5071b9114dSArnd Bergmann panic("Unknown S3C24XX CPU"); 5171b9114dSArnd Bergmann } 5271b9114dSArnd Bergmann 5371b9114dSArnd Bergmann printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); 5471b9114dSArnd Bergmann 5571b9114dSArnd Bergmann if (cpu->init == NULL) { 5671b9114dSArnd Bergmann printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); 5771b9114dSArnd Bergmann panic("Unsupported Samsung CPU"); 5871b9114dSArnd Bergmann } 5971b9114dSArnd Bergmann 6071b9114dSArnd Bergmann if (cpu->map_io) 6171b9114dSArnd Bergmann cpu->map_io(); 6271b9114dSArnd Bergmann } 6371b9114dSArnd Bergmann 6471b9114dSArnd Bergmann /* s3c24xx_init_clocks 6571b9114dSArnd Bergmann * 6671b9114dSArnd Bergmann * Initialise the clock subsystem and associated information from the 6771b9114dSArnd Bergmann * given master crystal value. 6871b9114dSArnd Bergmann * 6971b9114dSArnd Bergmann * xtal = 0 -> use default PLL crystal value (normally 12MHz) 7071b9114dSArnd Bergmann * != 0 -> PLL crystal value in Hz 7171b9114dSArnd Bergmann */ 7271b9114dSArnd Bergmann 7371b9114dSArnd Bergmann void __init s3c24xx_init_clocks(int xtal) 7471b9114dSArnd Bergmann { 7571b9114dSArnd Bergmann if (xtal == 0) 7671b9114dSArnd Bergmann xtal = 12*1000*1000; 7771b9114dSArnd Bergmann 7871b9114dSArnd Bergmann if (cpu == NULL) 7971b9114dSArnd Bergmann panic("s3c24xx_init_clocks: no cpu setup?\n"); 8071b9114dSArnd Bergmann 8171b9114dSArnd Bergmann if (cpu->init_clocks == NULL) 8271b9114dSArnd Bergmann panic("s3c24xx_init_clocks: cpu has no clock init\n"); 8371b9114dSArnd Bergmann else 8471b9114dSArnd Bergmann (cpu->init_clocks)(xtal); 8571b9114dSArnd Bergmann } 8671b9114dSArnd Bergmann 8771b9114dSArnd Bergmann /* uart management */ 8871b9114dSArnd Bergmann #if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) 8971b9114dSArnd Bergmann static int nr_uarts __initdata = 0; 9071b9114dSArnd Bergmann 9171b9114dSArnd Bergmann #ifdef CONFIG_SERIAL_SAMSUNG_UARTS 9271b9114dSArnd Bergmann static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS]; 9371b9114dSArnd Bergmann #endif 9471b9114dSArnd Bergmann 9571b9114dSArnd Bergmann /* s3c24xx_init_uartdevs 9671b9114dSArnd Bergmann * 9771b9114dSArnd Bergmann * copy the specified platform data and configuration into our central 9871b9114dSArnd Bergmann * set of devices, before the data is thrown away after the init process. 9971b9114dSArnd Bergmann * 10071b9114dSArnd Bergmann * This also fills in the array passed to the serial driver for the 10171b9114dSArnd Bergmann * early initialisation of the console. 10271b9114dSArnd Bergmann */ 10371b9114dSArnd Bergmann 10471b9114dSArnd Bergmann void __init s3c24xx_init_uartdevs(char *name, 10571b9114dSArnd Bergmann struct s3c24xx_uart_resources *res, 10671b9114dSArnd Bergmann struct s3c2410_uartcfg *cfg, int no) 10771b9114dSArnd Bergmann { 10871b9114dSArnd Bergmann #ifdef CONFIG_SERIAL_SAMSUNG_UARTS 10971b9114dSArnd Bergmann struct platform_device *platdev; 11071b9114dSArnd Bergmann struct s3c2410_uartcfg *cfgptr = uart_cfgs; 11171b9114dSArnd Bergmann struct s3c24xx_uart_resources *resp; 11271b9114dSArnd Bergmann int uart; 11371b9114dSArnd Bergmann 11471b9114dSArnd Bergmann memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no); 11571b9114dSArnd Bergmann 11671b9114dSArnd Bergmann for (uart = 0; uart < no; uart++, cfg++, cfgptr++) { 11771b9114dSArnd Bergmann platdev = s3c24xx_uart_src[cfgptr->hwport]; 11871b9114dSArnd Bergmann 11971b9114dSArnd Bergmann resp = res + cfgptr->hwport; 12071b9114dSArnd Bergmann 12171b9114dSArnd Bergmann s3c24xx_uart_devs[uart] = platdev; 12271b9114dSArnd Bergmann 12371b9114dSArnd Bergmann platdev->name = name; 12471b9114dSArnd Bergmann platdev->resource = resp->resources; 12571b9114dSArnd Bergmann platdev->num_resources = resp->nr_resources; 12671b9114dSArnd Bergmann 12771b9114dSArnd Bergmann platdev->dev.platform_data = cfgptr; 12871b9114dSArnd Bergmann } 12971b9114dSArnd Bergmann 13071b9114dSArnd Bergmann nr_uarts = no; 13171b9114dSArnd Bergmann #endif 13271b9114dSArnd Bergmann } 13371b9114dSArnd Bergmann 13471b9114dSArnd Bergmann void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) 13571b9114dSArnd Bergmann { 13671b9114dSArnd Bergmann if (cpu == NULL) 13771b9114dSArnd Bergmann return; 13871b9114dSArnd Bergmann 13971b9114dSArnd Bergmann if (cpu->init_uarts == NULL && IS_ENABLED(CONFIG_SAMSUNG_ATAGS)) { 14071b9114dSArnd Bergmann printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n"); 14171b9114dSArnd Bergmann } else 14271b9114dSArnd Bergmann (cpu->init_uarts)(cfg, no); 14371b9114dSArnd Bergmann } 14471b9114dSArnd Bergmann #endif 14571b9114dSArnd Bergmann 14671b9114dSArnd Bergmann static int __init s3c_arch_init(void) 14771b9114dSArnd Bergmann { 14871b9114dSArnd Bergmann int ret; 14971b9114dSArnd Bergmann 15071b9114dSArnd Bergmann /* init is only needed for ATAGS based platforms */ 15171b9114dSArnd Bergmann if (!IS_ENABLED(CONFIG_ATAGS) || 15271b9114dSArnd Bergmann (!soc_is_s3c24xx() && !soc_is_s3c64xx())) 15371b9114dSArnd Bergmann return 0; 15471b9114dSArnd Bergmann 15571b9114dSArnd Bergmann // do the correct init for cpu 15671b9114dSArnd Bergmann 15771b9114dSArnd Bergmann if (cpu == NULL) { 15871b9114dSArnd Bergmann /* Not needed when booting with device tree. */ 15971b9114dSArnd Bergmann if (of_have_populated_dt()) 16071b9114dSArnd Bergmann return 0; 16171b9114dSArnd Bergmann panic("s3c_arch_init: NULL cpu\n"); 16271b9114dSArnd Bergmann } 16371b9114dSArnd Bergmann 16471b9114dSArnd Bergmann ret = (cpu->init)(); 16571b9114dSArnd Bergmann if (ret != 0) 16671b9114dSArnd Bergmann return ret; 16771b9114dSArnd Bergmann #if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) 16871b9114dSArnd Bergmann ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); 16971b9114dSArnd Bergmann #endif 17071b9114dSArnd Bergmann return ret; 17171b9114dSArnd Bergmann } 17271b9114dSArnd Bergmann 17371b9114dSArnd Bergmann arch_initcall(s3c_arch_init); 174