forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
4.9 KiB
248 lines
4.9 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* 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/setup.h> |
|
#include <asm/mach-au1x00/au1000.h> |
|
#include <asm/mach-db1x00/bcsr.h> |
|
|
|
#include <prom.h> |
|
|
|
void prom_putchar(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 = kcalloc(cnt, sizeof(struct resource), 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 = kcalloc(5, sizeof(struct mtd_partition), 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; |
|
}
|
|
|