| /* |
| * devoard misc stuff. |
| */ |
| |
| #include <linux/init.h> |
| #include <linux/mtd/mtd.h> |
| #include <linux/mtd/map.h> |
| #include <linux/mtd/physmap.h> |
| #include <linux/slab.h> |
| #include <linux/platform_device.h> |
| #include <linux/pm.h> |
| |
| #include <asm/bootinfo.h> |
| #include <asm/idle.h> |
| #include <asm/reboot.h> |
| #include <asm/mach-au1x00/au1000.h> |
| #include <asm/mach-db1x00/bcsr.h> |
| |
| #include <prom.h> |
| |
| void __init prom_init(void) |
| { |
| unsigned char *memsize_str; |
| unsigned long memsize; |
| |
| prom_argc = (int)fw_arg0; |
| prom_argv = (char **)fw_arg1; |
| prom_envp = (char **)fw_arg2; |
| |
| prom_init_cmdline(); |
| memsize_str = prom_getenv("memsize"); |
| if (!memsize_str || kstrtoul(memsize_str, 0, &memsize)) |
| memsize = 64 << 20; /* all devboards have at least 64MB RAM */ |
| |
| add_memory_region(0, memsize, BOOT_MEM_RAM); |
| } |
| |
| void prom_putchar(unsigned char c) |
| { |
| if (alchemy_get_cputype() == ALCHEMY_CPU_AU1300) |
| alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c); |
| else |
| alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); |
| } |
| |
| |
| static struct platform_device db1x00_rtc_dev = { |
| .name = "rtc-au1xxx", |
| .id = -1, |
| }; |
| |
| |
| static void db1x_power_off(void) |
| { |
| bcsr_write(BCSR_RESETS, 0); |
| bcsr_write(BCSR_SYSTEM, BCSR_SYSTEM_PWROFF | BCSR_SYSTEM_RESET); |
| while (1) /* sit and spin */ |
| cpu_wait(); |
| } |
| |
| static void db1x_reset(char *c) |
| { |
| bcsr_write(BCSR_RESETS, 0); |
| bcsr_write(BCSR_SYSTEM, 0); |
| } |
| |
| static int __init db1x_late_setup(void) |
| { |
| if (!pm_power_off) |
| pm_power_off = db1x_power_off; |
| if (!_machine_halt) |
| _machine_halt = db1x_power_off; |
| if (!_machine_restart) |
| _machine_restart = db1x_reset; |
| |
| platform_device_register(&db1x00_rtc_dev); |
| |
| return 0; |
| } |
| device_initcall(db1x_late_setup); |
| |
| /* register a pcmcia socket */ |
| int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start, |
| phys_addr_t pcmcia_attr_end, |
| phys_addr_t pcmcia_mem_start, |
| phys_addr_t pcmcia_mem_end, |
| phys_addr_t pcmcia_io_start, |
| phys_addr_t pcmcia_io_end, |
| int card_irq, |
| int cd_irq, |
| int stschg_irq, |
| int eject_irq, |
| int id) |
| { |
| int cnt, i, ret; |
| struct resource *sr; |
| struct platform_device *pd; |
| |
| cnt = 5; |
| if (eject_irq) |
| cnt++; |
| if (stschg_irq) |
| cnt++; |
| |
| sr = kzalloc(sizeof(struct resource) * cnt, GFP_KERNEL); |
| if (!sr) |
| return -ENOMEM; |
| |
| pd = platform_device_alloc("db1xxx_pcmcia", id); |
| if (!pd) { |
| ret = -ENOMEM; |
| goto out; |
| } |
| |
| sr[0].name = "pcmcia-attr"; |
| sr[0].flags = IORESOURCE_MEM; |
| sr[0].start = pcmcia_attr_start; |
| sr[0].end = pcmcia_attr_end; |
| |
| sr[1].name = "pcmcia-mem"; |
| sr[1].flags = IORESOURCE_MEM; |
| sr[1].start = pcmcia_mem_start; |
| sr[1].end = pcmcia_mem_end; |
| |
| sr[2].name = "pcmcia-io"; |
| sr[2].flags = IORESOURCE_MEM; |
| sr[2].start = pcmcia_io_start; |
| sr[2].end = pcmcia_io_end; |
| |
| sr[3].name = "insert"; |
| sr[3].flags = IORESOURCE_IRQ; |
| sr[3].start = sr[3].end = cd_irq; |
| |
| sr[4].name = "card"; |
| sr[4].flags = IORESOURCE_IRQ; |
| sr[4].start = sr[4].end = card_irq; |
| |
| i = 5; |
| if (stschg_irq) { |
| sr[i].name = "stschg"; |
| sr[i].flags = IORESOURCE_IRQ; |
| sr[i].start = sr[i].end = stschg_irq; |
| i++; |
| } |
| if (eject_irq) { |
| sr[i].name = "eject"; |
| sr[i].flags = IORESOURCE_IRQ; |
| sr[i].start = sr[i].end = eject_irq; |
| } |
| |
| pd->resource = sr; |
| pd->num_resources = cnt; |
| |
| ret = platform_device_add(pd); |
| if (!ret) |
| return 0; |
| |
| platform_device_put(pd); |
| out: |
| kfree(sr); |
| return ret; |
| } |
| |
| #define YAMON_SIZE 0x00100000 |
| #define YAMON_ENV_SIZE 0x00040000 |
| |
| int __init db1x_register_norflash(unsigned long size, int width, |
| int swapped) |
| { |
| struct physmap_flash_data *pfd; |
| struct platform_device *pd; |
| struct mtd_partition *parts; |
| struct resource *res; |
| int ret, i; |
| |
| if (size < (8 * 1024 * 1024)) |
| return -EINVAL; |
| |
| ret = -ENOMEM; |
| parts = kzalloc(sizeof(struct mtd_partition) * 5, GFP_KERNEL); |
| if (!parts) |
| goto out; |
| |
| res = kzalloc(sizeof(struct resource), GFP_KERNEL); |
| if (!res) |
| goto out1; |
| |
| pfd = kzalloc(sizeof(struct physmap_flash_data), GFP_KERNEL); |
| if (!pfd) |
| goto out2; |
| |
| pd = platform_device_alloc("physmap-flash", 0); |
| if (!pd) |
| goto out3; |
| |
| /* NOR flash ends at 0x20000000, regardless of size */ |
| res->start = 0x20000000 - size; |
| res->end = 0x20000000 - 1; |
| res->flags = IORESOURCE_MEM; |
| |
| /* partition setup. Most Develboards have a switch which allows |
| * to swap the physical locations of the 2 NOR flash banks. |
| */ |
| i = 0; |
| if (!swapped) { |
| /* first NOR chip */ |
| parts[i].offset = 0; |
| parts[i].name = "User FS"; |
| parts[i].size = size / 2; |
| i++; |
| } |
| |
| parts[i].offset = MTDPART_OFS_APPEND; |
| parts[i].name = "User FS 2"; |
| parts[i].size = (size / 2) - (0x20000000 - 0x1fc00000); |
| i++; |
| |
| parts[i].offset = MTDPART_OFS_APPEND; |
| parts[i].name = "YAMON"; |
| parts[i].size = YAMON_SIZE; |
| parts[i].mask_flags = MTD_WRITEABLE; |
| i++; |
| |
| parts[i].offset = MTDPART_OFS_APPEND; |
| parts[i].name = "raw kernel"; |
| parts[i].size = 0x00400000 - YAMON_SIZE - YAMON_ENV_SIZE; |
| i++; |
| |
| parts[i].offset = MTDPART_OFS_APPEND; |
| parts[i].name = "YAMON Env"; |
| parts[i].size = YAMON_ENV_SIZE; |
| parts[i].mask_flags = MTD_WRITEABLE; |
| i++; |
| |
| if (swapped) { |
| parts[i].offset = MTDPART_OFS_APPEND; |
| parts[i].name = "User FS"; |
| parts[i].size = size / 2; |
| i++; |
| } |
| |
| pfd->width = width; |
| pfd->parts = parts; |
| pfd->nr_parts = 5; |
| |
| pd->dev.platform_data = pfd; |
| pd->resource = res; |
| pd->num_resources = 1; |
| |
| ret = platform_device_add(pd); |
| if (!ret) |
| return ret; |
| |
| platform_device_put(pd); |
| out3: |
| kfree(pfd); |
| out2: |
| kfree(res); |
| out1: |
| kfree(parts); |
| out: |
| return ret; |
| } |