From 8e90d12946f9e858442c7079791ae99b0ed6dfd8 Mon Sep 17 00:00:00 2001 From: Fredrik Noring Date: Sat, 10 Jul 2021 18:12:26 +0200 Subject: [PATCH] FIXME: dev9 module --- drivers/ps2/Makefile | 1 + drivers/ps2/iop-dev9.c | 343 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 drivers/ps2/iop-dev9.c diff --git a/drivers/ps2/Makefile b/drivers/ps2/Makefile index 57a01367ad8422..38bcd6d7cde9b3 100644 --- a/drivers/ps2/Makefile +++ b/drivers/ps2/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_PS2_GS) += gs-irq.o obj-$(CONFIG_PS2_GS) += gs-registers.o obj-$(CONFIG_PS2_GS) += gs-sysfs.o +obj-m += iop-dev9.o obj-m += iop-heap.o obj-m += iop-irq.o obj-m += iop-memory.o diff --git a/drivers/ps2/iop-dev9.c b/drivers/ps2/iop-dev9.c new file mode 100644 index 00000000000000..577e806ae77ee5 --- /dev/null +++ b/drivers/ps2/iop-dev9.c @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PlayStation 2 I/O processor (IOP) DEV9 + * + * Copyright (C) 2018 Fredrik Noring + */ + +#include +#include +#include +#include + +#include + +#include "iop-module.h" + +static struct { + u16 rev; +} dev9; + +#define DEFINE_READW_REG(type, reg, name) \ + static inline int iop_##type##_read_##name(u16 * const value) \ + { \ + return iop_readw(value, 0xbf800000 + (reg)); \ + } + +#define DEFINE_WRITEW_REG(type, reg, name) \ + static inline int iop_##type##_write_##name(const u16 value) \ + { \ + return iop_writew(value, 0xbf800000 + (reg)); \ + } + +#define DEFINE_READL_REG(type, reg, name) \ + static inline int iop_##type##_read_##name(u32 * const value) \ + { \ + return iop_readl(value, 0xbf800000 + (reg)); \ + } + +#define DEFINE_WRITEL_REG(type, reg, name) \ + static inline int iop_##type##_write_##name(const u32 value) \ + { \ + return iop_writel(value, 0xbf800000 + (reg)); \ + } + +#define DEFINE_DEV9_READ_WRITE_REG(reg, name) \ + DEFINE_READW_REG(dev9, reg, name); \ + DEFINE_WRITEW_REG(dev9, reg, name) + +#define DEFINE_SSBUS_READ_WRITE_REG(reg, name) \ + DEFINE_READL_REG(ssbus, reg, name); \ + DEFINE_WRITEL_REG(ssbus, reg, name) + +DEFINE_DEV9_READ_WRITE_REG(0x1460, 1460); +DEFINE_DEV9_READ_WRITE_REG(0x1462, 1462); +DEFINE_DEV9_READ_WRITE_REG(0x1464, 1464); +DEFINE_DEV9_READ_WRITE_REG(0x1466, 1466); +DEFINE_DEV9_READ_WRITE_REG(0x1468, 1468); +DEFINE_DEV9_READ_WRITE_REG(0x146a, 146a); +DEFINE_DEV9_READ_WRITE_REG(0x146c, power); +DEFINE_DEV9_READ_WRITE_REG(0x146e, rev); +DEFINE_DEV9_READ_WRITE_REG(0x1470, 1470); +DEFINE_DEV9_READ_WRITE_REG(0x1472, 1472); +DEFINE_DEV9_READ_WRITE_REG(0x1474, 1474); +DEFINE_DEV9_READ_WRITE_REG(0x1476, 1476); +DEFINE_DEV9_READ_WRITE_REG(0x1478, 1478); +DEFINE_DEV9_READ_WRITE_REG(0x147a, 147a); +DEFINE_DEV9_READ_WRITE_REG(0x147c, 147c); +DEFINE_DEV9_READ_WRITE_REG(0x147e, 147e); + +DEFINE_SSBUS_READ_WRITE_REG(0x1418, 1418); +DEFINE_SSBUS_READ_WRITE_REG(0x141c, 141c); +DEFINE_SSBUS_READ_WRITE_REG(0x1420, 1420); + +static bool pc_card(void) +{ + return (dev9.rev & 0xf0) == 0x20; +} + +static bool exp_dev(void) +{ + return (dev9.rev & 0xf0) == 0x30; +} + +static int iop_dev9_power(bool * const power) +{ + u16 raw; + int err; + + err = iop_dev9_read_power(&raw); + if (err < 0) { + *power = false; + return err; + } + + *power = ((raw & 0x4) != 0); + + return 0; +} + +static int __init exp_dev_probe(void) +{ + u16 reg_1462; + int err; + + err = iop_dev9_read_1462(®_1462); + if (err < 0) + return err; + + return (reg_1462 & 0x1) ? -ENODEV : 0; +} + +static int __init exp_dev_reset(void) +{ + u16 reg_power; + u16 reg_1460; + int err; + + err = exp_dev_probe(); + if (err < 0) + return err; + + err = iop_dev9_read_power(®_power); /* FIXME: iop_dev9_ -> dev9_ */ + if (err < 0) + return err; + + err = iop_dev9_write_power((reg_power & ~0x1) | 0x4); + if (err < 0) + return err; + + msleep(500); /* FIXME */ + + err = iop_dev9_read_1460(®_1460); + if (err < 0) + return err; + + err = iop_dev9_write_1460(reg_1460 | 0x1); + if (err < 0) + return err; + + err = iop_dev9_read_power(®_power); + if (err < 0) + return err; + + err = iop_dev9_write_power(reg_power | 0x1); + if (err < 0) + return err; + + msleep(500); /* FIXME */ + + return 0; +} + +static int __init exp_dev_init(void) +{ + bool power; + int err; + + err = iop_ssbus_write_1420(0x51011); + if (err < 0) + return err; + + err = iop_ssbus_write_1418(0xe01a3043); + if (err < 0) + return err; + + err = iop_ssbus_write_141c(0xef1a3043); + if (err < 0) + return err; + + err = iop_dev9_power(&power); + if (err < 0) + return err; + + if (!power) + { + u16 reg_1464; + + printk("dev9: Expansion device power on\n"); /* FIXME */ + + err = iop_dev9_write_1466(1); + if (err < 0) + return err; + + err = iop_dev9_write_1464(0); + if (err < 0) + return err; + + err = iop_dev9_read_1464(®_1464); + if (err < 0) + return err; + + err = iop_dev9_write_1460(reg_1464); + if (err < 0) + return err; + + err = exp_dev_reset(); + if (err < 0) + return err; + } else { + printk("dev9: Expansion device already powered on\n"); /* FIXME */ + } + +#if 0 + err = iop_dev9_write_1464(0x103 & 0x3f); /* ??? */ + if (err < 0) + return err; +#endif + + err = iop_dev9_write_1466(0); + if (err < 0) + return err; + + iop_set_dma_dpcr2(IOP_DMA_DPCR2_DEV9); + + return 0; +} + +static inline u16 iop_speed_read_rev1(void) { return inw(0x14000002); } +static inline u16 iop_speed_read_rev3(void) { return inw(0x14000004); } +static inline u16 iop_speed_read_rev8(void) { return inw(0x1400000e); } + +static void rev_test(void) +{ + u16 rev; + int err; + + err = iop_readw(&rev, 0xb0000002); + if (err < 0) + goto out; + printk("rev-test: rev1 %x\n", rev); + + err = iop_readw(&rev, 0xb0000004); + if (err < 0) + goto out; + printk("rev-test: rev3 %x\n", rev); + + err = iop_readw(&rev, 0xb000000e); + if (err < 0) + goto out; + printk("rev-test: rev8 %x\n", rev); + +out: + if (err) + printk("rev-test: Failed with %d\n", err); +} + +static int __init iop_dev9_init(void) +{ + int err; + + err = iop_dev9_read_rev(&dev9.rev); + if (err < 0) { + printk("iop_dev9_init: err %d\n", err); + return err; + } + + if (pc_card()) { + printk("dev9: PC card interface is not implemented\n"); + return -EINVAL; + } else if (exp_dev()) { + printk("dev9: Expansion device interface\n"); + err = exp_dev_init(); + } else { + printk("dev9: Unknown interface %x\n", dev9.rev); + return -EINVAL; + } + + if (err < 0) { + printk("dev9: Initialization failed with %d\n", err); + return err; + } + +#if 0 + err = iop_dev9_write_1464(3); /* Activate network */ + if (err < 0) + return err; +#endif + + printk("dev9: Interface initialized\n"); + + printk("dev9: speed: %x %x %x\n", + iop_speed_read_rev1(), + iop_speed_read_rev3(), + iop_speed_read_rev8()); + rev_test(); + + return 0; +} + +static void __exit iop_dev9_exit(void) +{ + int err = 0; + + if (pc_card()) { + /* FIXME */ + } else if (exp_dev()) { + u16 reg_power; + u16 reg_1464; + + printk("dev9: Expansion device power off\n"); /* FIXME */ + + err = iop_dev9_write_1466(1); + if (err < 0) + goto out; + + err = iop_dev9_write_1464(0); + if (err < 0) + goto out; + + err = iop_dev9_read_1464(®_1464); + if (err < 0) + goto out; + + err = iop_dev9_write_1460(reg_1464); + if (err < 0) + goto out; + + err = iop_dev9_read_power(®_power); + if (err < 0) + goto out; + + err = iop_dev9_write_power(reg_power & ~0x4); + if (err < 0) + goto out; + + err = iop_dev9_read_power(®_power); + if (err < 0) + goto out; + + err = iop_dev9_write_power(reg_power & ~0x1); + if (err < 0) + goto out; + } + +out: + if (err) + printk("dev9: Exit failed with %d\n", err); +} + +module_init(iop_dev9_init); +module_exit(iop_dev9_exit); + +MODULE_LICENSE("GPL");