linux/linux-5.18.11/arch/mips/alchemy/devboards/platform.c

249 lines
4.9 KiB
C

// 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;
}