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