18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * devoard misc stuff. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/init.h> 78c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 88c2ecf20Sopenharmony_ci#include <linux/mtd/map.h> 98c2ecf20Sopenharmony_ci#include <linux/mtd/physmap.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/pm.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 158c2ecf20Sopenharmony_ci#include <asm/idle.h> 168c2ecf20Sopenharmony_ci#include <asm/reboot.h> 178c2ecf20Sopenharmony_ci#include <asm/setup.h> 188c2ecf20Sopenharmony_ci#include <asm/mach-au1x00/au1000.h> 198c2ecf20Sopenharmony_ci#include <asm/mach-db1x00/bcsr.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <prom.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_civoid prom_putchar(char c) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (alchemy_get_cputype() == ALCHEMY_CPU_AU1300) 268c2ecf20Sopenharmony_ci alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c); 278c2ecf20Sopenharmony_ci else 288c2ecf20Sopenharmony_ci alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct platform_device db1x00_rtc_dev = { 338c2ecf20Sopenharmony_ci .name = "rtc-au1xxx", 348c2ecf20Sopenharmony_ci .id = -1, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void db1x_power_off(void) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci bcsr_write(BCSR_RESETS, 0); 418c2ecf20Sopenharmony_ci bcsr_write(BCSR_SYSTEM, BCSR_SYSTEM_PWROFF | BCSR_SYSTEM_RESET); 428c2ecf20Sopenharmony_ci while (1) /* sit and spin */ 438c2ecf20Sopenharmony_ci cpu_wait(); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void db1x_reset(char *c) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci bcsr_write(BCSR_RESETS, 0); 498c2ecf20Sopenharmony_ci bcsr_write(BCSR_SYSTEM, 0); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int __init db1x_late_setup(void) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (!pm_power_off) 558c2ecf20Sopenharmony_ci pm_power_off = db1x_power_off; 568c2ecf20Sopenharmony_ci if (!_machine_halt) 578c2ecf20Sopenharmony_ci _machine_halt = db1x_power_off; 588c2ecf20Sopenharmony_ci if (!_machine_restart) 598c2ecf20Sopenharmony_ci _machine_restart = db1x_reset; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci platform_device_register(&db1x00_rtc_dev); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_cidevice_initcall(db1x_late_setup); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* register a pcmcia socket */ 688c2ecf20Sopenharmony_ciint __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start, 698c2ecf20Sopenharmony_ci phys_addr_t pcmcia_attr_end, 708c2ecf20Sopenharmony_ci phys_addr_t pcmcia_mem_start, 718c2ecf20Sopenharmony_ci phys_addr_t pcmcia_mem_end, 728c2ecf20Sopenharmony_ci phys_addr_t pcmcia_io_start, 738c2ecf20Sopenharmony_ci phys_addr_t pcmcia_io_end, 748c2ecf20Sopenharmony_ci int card_irq, 758c2ecf20Sopenharmony_ci int cd_irq, 768c2ecf20Sopenharmony_ci int stschg_irq, 778c2ecf20Sopenharmony_ci int eject_irq, 788c2ecf20Sopenharmony_ci int id) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int cnt, i, ret; 818c2ecf20Sopenharmony_ci struct resource *sr; 828c2ecf20Sopenharmony_ci struct platform_device *pd; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci cnt = 5; 858c2ecf20Sopenharmony_ci if (eject_irq) 868c2ecf20Sopenharmony_ci cnt++; 878c2ecf20Sopenharmony_ci if (stschg_irq) 888c2ecf20Sopenharmony_ci cnt++; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci sr = kcalloc(cnt, sizeof(struct resource), GFP_KERNEL); 918c2ecf20Sopenharmony_ci if (!sr) 928c2ecf20Sopenharmony_ci return -ENOMEM; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci pd = platform_device_alloc("db1xxx_pcmcia", id); 958c2ecf20Sopenharmony_ci if (!pd) { 968c2ecf20Sopenharmony_ci ret = -ENOMEM; 978c2ecf20Sopenharmony_ci goto out; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci sr[0].name = "pcmcia-attr"; 1018c2ecf20Sopenharmony_ci sr[0].flags = IORESOURCE_MEM; 1028c2ecf20Sopenharmony_ci sr[0].start = pcmcia_attr_start; 1038c2ecf20Sopenharmony_ci sr[0].end = pcmcia_attr_end; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci sr[1].name = "pcmcia-mem"; 1068c2ecf20Sopenharmony_ci sr[1].flags = IORESOURCE_MEM; 1078c2ecf20Sopenharmony_ci sr[1].start = pcmcia_mem_start; 1088c2ecf20Sopenharmony_ci sr[1].end = pcmcia_mem_end; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci sr[2].name = "pcmcia-io"; 1118c2ecf20Sopenharmony_ci sr[2].flags = IORESOURCE_MEM; 1128c2ecf20Sopenharmony_ci sr[2].start = pcmcia_io_start; 1138c2ecf20Sopenharmony_ci sr[2].end = pcmcia_io_end; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci sr[3].name = "insert"; 1168c2ecf20Sopenharmony_ci sr[3].flags = IORESOURCE_IRQ; 1178c2ecf20Sopenharmony_ci sr[3].start = sr[3].end = cd_irq; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci sr[4].name = "card"; 1208c2ecf20Sopenharmony_ci sr[4].flags = IORESOURCE_IRQ; 1218c2ecf20Sopenharmony_ci sr[4].start = sr[4].end = card_irq; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci i = 5; 1248c2ecf20Sopenharmony_ci if (stschg_irq) { 1258c2ecf20Sopenharmony_ci sr[i].name = "stschg"; 1268c2ecf20Sopenharmony_ci sr[i].flags = IORESOURCE_IRQ; 1278c2ecf20Sopenharmony_ci sr[i].start = sr[i].end = stschg_irq; 1288c2ecf20Sopenharmony_ci i++; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci if (eject_irq) { 1318c2ecf20Sopenharmony_ci sr[i].name = "eject"; 1328c2ecf20Sopenharmony_ci sr[i].flags = IORESOURCE_IRQ; 1338c2ecf20Sopenharmony_ci sr[i].start = sr[i].end = eject_irq; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci pd->resource = sr; 1378c2ecf20Sopenharmony_ci pd->num_resources = cnt; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci ret = platform_device_add(pd); 1408c2ecf20Sopenharmony_ci if (!ret) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci platform_device_put(pd); 1448c2ecf20Sopenharmony_ciout: 1458c2ecf20Sopenharmony_ci kfree(sr); 1468c2ecf20Sopenharmony_ci return ret; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#define YAMON_SIZE 0x00100000 1508c2ecf20Sopenharmony_ci#define YAMON_ENV_SIZE 0x00040000 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciint __init db1x_register_norflash(unsigned long size, int width, 1538c2ecf20Sopenharmony_ci int swapped) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct physmap_flash_data *pfd; 1568c2ecf20Sopenharmony_ci struct platform_device *pd; 1578c2ecf20Sopenharmony_ci struct mtd_partition *parts; 1588c2ecf20Sopenharmony_ci struct resource *res; 1598c2ecf20Sopenharmony_ci int ret, i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (size < (8 * 1024 * 1024)) 1628c2ecf20Sopenharmony_ci return -EINVAL; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ret = -ENOMEM; 1658c2ecf20Sopenharmony_ci parts = kcalloc(5, sizeof(struct mtd_partition), GFP_KERNEL); 1668c2ecf20Sopenharmony_ci if (!parts) 1678c2ecf20Sopenharmony_ci goto out; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci res = kzalloc(sizeof(struct resource), GFP_KERNEL); 1708c2ecf20Sopenharmony_ci if (!res) 1718c2ecf20Sopenharmony_ci goto out1; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci pfd = kzalloc(sizeof(struct physmap_flash_data), GFP_KERNEL); 1748c2ecf20Sopenharmony_ci if (!pfd) 1758c2ecf20Sopenharmony_ci goto out2; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci pd = platform_device_alloc("physmap-flash", 0); 1788c2ecf20Sopenharmony_ci if (!pd) 1798c2ecf20Sopenharmony_ci goto out3; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* NOR flash ends at 0x20000000, regardless of size */ 1828c2ecf20Sopenharmony_ci res->start = 0x20000000 - size; 1838c2ecf20Sopenharmony_ci res->end = 0x20000000 - 1; 1848c2ecf20Sopenharmony_ci res->flags = IORESOURCE_MEM; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* partition setup. Most Develboards have a switch which allows 1878c2ecf20Sopenharmony_ci * to swap the physical locations of the 2 NOR flash banks. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci i = 0; 1908c2ecf20Sopenharmony_ci if (!swapped) { 1918c2ecf20Sopenharmony_ci /* first NOR chip */ 1928c2ecf20Sopenharmony_ci parts[i].offset = 0; 1938c2ecf20Sopenharmony_ci parts[i].name = "User FS"; 1948c2ecf20Sopenharmony_ci parts[i].size = size / 2; 1958c2ecf20Sopenharmony_ci i++; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci parts[i].offset = MTDPART_OFS_APPEND; 1998c2ecf20Sopenharmony_ci parts[i].name = "User FS 2"; 2008c2ecf20Sopenharmony_ci parts[i].size = (size / 2) - (0x20000000 - 0x1fc00000); 2018c2ecf20Sopenharmony_ci i++; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci parts[i].offset = MTDPART_OFS_APPEND; 2048c2ecf20Sopenharmony_ci parts[i].name = "YAMON"; 2058c2ecf20Sopenharmony_ci parts[i].size = YAMON_SIZE; 2068c2ecf20Sopenharmony_ci parts[i].mask_flags = MTD_WRITEABLE; 2078c2ecf20Sopenharmony_ci i++; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci parts[i].offset = MTDPART_OFS_APPEND; 2108c2ecf20Sopenharmony_ci parts[i].name = "raw kernel"; 2118c2ecf20Sopenharmony_ci parts[i].size = 0x00400000 - YAMON_SIZE - YAMON_ENV_SIZE; 2128c2ecf20Sopenharmony_ci i++; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci parts[i].offset = MTDPART_OFS_APPEND; 2158c2ecf20Sopenharmony_ci parts[i].name = "YAMON Env"; 2168c2ecf20Sopenharmony_ci parts[i].size = YAMON_ENV_SIZE; 2178c2ecf20Sopenharmony_ci parts[i].mask_flags = MTD_WRITEABLE; 2188c2ecf20Sopenharmony_ci i++; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (swapped) { 2218c2ecf20Sopenharmony_ci parts[i].offset = MTDPART_OFS_APPEND; 2228c2ecf20Sopenharmony_ci parts[i].name = "User FS"; 2238c2ecf20Sopenharmony_ci parts[i].size = size / 2; 2248c2ecf20Sopenharmony_ci i++; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci pfd->width = width; 2288c2ecf20Sopenharmony_ci pfd->parts = parts; 2298c2ecf20Sopenharmony_ci pfd->nr_parts = 5; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci pd->dev.platform_data = pfd; 2328c2ecf20Sopenharmony_ci pd->resource = res; 2338c2ecf20Sopenharmony_ci pd->num_resources = 1; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ret = platform_device_add(pd); 2368c2ecf20Sopenharmony_ci if (!ret) 2378c2ecf20Sopenharmony_ci return ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci platform_device_put(pd); 2408c2ecf20Sopenharmony_ciout3: 2418c2ecf20Sopenharmony_ci kfree(pfd); 2428c2ecf20Sopenharmony_ciout2: 2438c2ecf20Sopenharmony_ci kfree(res); 2448c2ecf20Sopenharmony_ciout1: 2458c2ecf20Sopenharmony_ci kfree(parts); 2468c2ecf20Sopenharmony_ciout: 2478c2ecf20Sopenharmony_ci return ret; 2488c2ecf20Sopenharmony_ci} 249