MCR3000 board has some components tied to the SPI bus, like the Texas
Instruments LM74 temperature sensor.

Add support for SPI bus. The SPI chipselects are a bit special in the
way that they are driven by 3 bits in a register of the board's CPLD
where the value writen in those bits exclusively activates one of the
7 possible chipselects and value 0 sets all chipselets to inactive.

So add a special GPIO driver that simulates GPIOs for those chipselect.

Signed-off-by: Christophe Leroy <christophe.le...@csgroup.eu>
---
 arch/powerpc/dts/mcr3000.dts      |  31 +++++++++
 board/cssi/mcr3000/Makefile       |   1 +
 board/cssi/mcr3000/mcr3000.c      |   5 ++
 board/cssi/mcr3000/mcr3000_gpio.c | 109 ++++++++++++++++++++++++++++++
 configs/MCR3000_defconfig         |   5 ++
 5 files changed, 151 insertions(+)
 create mode 100644 board/cssi/mcr3000/mcr3000_gpio.c

diff --git a/arch/powerpc/dts/mcr3000.dts b/arch/powerpc/dts/mcr3000.dts
index c4d7737bc6..edcd8358d0 100644
--- a/arch/powerpc/dts/mcr3000.dts
+++ b/arch/powerpc/dts/mcr3000.dts
@@ -26,6 +26,37 @@
                        timeout-sec = <2>;
                        hw_margin_ms = <1000>;
                };
+
+               spi: spi@aa0 {
+                       status = "okay";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <0>;
+                       compatible = "fsl,mpc8xx-spi";
+               };
+       };
+
+       localbus@ff000100 {
+               compatible = "s3k,mcr3000-localbus", "fsl,pq1-localbus", 
"simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0xff000100 0x40>;                // ORx and BRx register
+
+               ranges = <0 0 0x04000000 0x04000000 // BOOT
+                         1 0 0x00000000 0x04000000 // SDRAM
+                         2 0 0x08000000 0x04000000 // RAMDP
+                         3 0 0x0C000000 0x04000000 // NAND
+                         4 0 0x10000000 0x04000000 // Periphs
+                         5 0 0x14000000 0x04000000 // FPGA
+                         6 0 0x18000000 0x04000000 // mezzanine
+                         7 0 0x1c000000 0x04000000>; // DSP
+
+               csspi: gpio-controller@2 {
+                       #gpio-cells = <2>;
+                       compatible = "s3k,mcr3000-cpld-csspi";
+                       reg = <4 0x802 2>;
+                       gpio-controller;
+               };
        };
 
        SERIAL: smc@0 {
diff --git a/board/cssi/mcr3000/Makefile b/board/cssi/mcr3000/Makefile
index 7803016af3..846fd680e9 100644
--- a/board/cssi/mcr3000/Makefile
+++ b/board/cssi/mcr3000/Makefile
@@ -6,3 +6,4 @@
 
 obj-y += mcr3000.o
 obj-$(CONFIG_CMD_NAND) += nand.o
+obj-$(CONFIG_MPC8XX_SPI) += mcr3000_gpio.o
diff --git a/board/cssi/mcr3000/mcr3000.c b/board/cssi/mcr3000/mcr3000.c
index 8857c9e42c..537d7fa124 100644
--- a/board/cssi/mcr3000/mcr3000.c
+++ b/board/cssi/mcr3000/mcr3000.c
@@ -116,6 +116,11 @@ int misc_init_r(void)
        clrbits_be16(&iop->iop_pcpar, 0x4);
        clrbits_be16(&iop->iop_pcdir, 0x4);
 
+       /* Activate SPI */
+       clrsetbits_be32(&immr->im_cpm.cp_pbpar, 0x1, 0xe);
+       setbits_be32(&immr->im_cpm.cp_pbdir, 0xf);
+       clrbits_be32(&immr->im_cpm.cp_pbdat, 0x1);
+
        /* if BTN_ACQ_AL is pressed then bootdelay is changed to 60 second */
        if ((in_be16(&iop->iop_pcdat) & 0x0004) == 0)
                env_set("bootdelay", "60");
diff --git a/board/cssi/mcr3000/mcr3000_gpio.c 
b/board/cssi/mcr3000/mcr3000_gpio.c
new file mode 100644
index 0000000000..2bba14e6e5
--- /dev/null
+++ b/board/cssi/mcr3000/mcr3000_gpio.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2024 CS GROUP France
+ *     Christophe Leroy <christophe.le...@csgroup.eu>
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <asm/gpio.h>
+#include <malloc.h>
+
+#include "../common/common.h"
+
+struct mcr3000_spi_gpio_plat {
+       ulong addr;
+};
+
+struct mcr3000_spi_gpio_data {
+       void __iomem *base;
+};
+
+static int mcr3000_spi_gpio_set_value(struct udevice *dev, uint gpio, int 
value)
+{
+       struct mcr3000_spi_gpio_data *data = dev_get_priv(dev);
+
+       if (value)
+               clrsetbits_be16(data->base, 7 << 5, (gpio & 7) << 5);
+       else
+               clrbits_be16(data->base, 7 << 5);
+
+       return 0;
+}
+
+static int mcr3000_spi_gpio_get_value(struct udevice *dev, uint gpio)
+{
+       struct mcr3000_spi_gpio_data *data = dev_get_priv(dev);
+
+       return gpio == ((in_be16(data->base) >> 5) & 7);
+}
+
+static int mcr3000_spi_gpio_direction_input(struct udevice *dev, uint gpio)
+{
+       return 0;
+}
+
+static int mcr3000_spi_gpio_get_function(struct udevice *dev, uint gpio)
+{
+       return GPIOF_OUTPUT;
+}
+
+static int mcr3000_spi_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+       struct mcr3000_spi_gpio_plat *plat = dev_get_plat(dev);
+       fdt_addr_t addr;
+       u32 reg[2];
+
+       dev_read_u32_array(dev, "reg", reg, 2);
+       addr = dev_translate_address(dev, reg);
+
+       plat->addr = addr;
+
+       return 0;
+}
+
+static int mcr3000_spi_gpio_probe(struct udevice *dev)
+{
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct mcr3000_spi_gpio_data *data = dev_get_priv(dev);
+       struct mcr3000_spi_gpio_plat *plat = dev_get_plat(dev);
+       char name[32], *str;
+
+       data->base = map_sysmem(plat->addr, 2);
+
+       snprintf(name, sizeof(name), "CHIPSELECT@%lx_", plat->addr);
+       str = strdup(name);
+
+       if (!str)
+               return -ENOMEM;
+
+       uc_priv->bank_name = str;
+       uc_priv->gpio_count = 16;
+
+       return 0;
+}
+
+static const struct dm_gpio_ops gpio_mcr3000_spi_ops = {
+       .get_value              = mcr3000_spi_gpio_get_value,
+       .set_value              = mcr3000_spi_gpio_set_value,
+       .direction_input        = mcr3000_spi_gpio_direction_input,
+       .direction_output       = mcr3000_spi_gpio_set_value,
+       .get_function           = mcr3000_spi_gpio_get_function,
+};
+
+static const struct udevice_id mcr3000_spi_gpio_ids[] = {
+       { .compatible = "s3k,mcr3000-cpld-csspi"},
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mcr3000_spi_gpio) = {
+       .name   = "mcr3000_spi_chipselect",
+       .id     = UCLASS_GPIO,
+       .ops    = &gpio_mcr3000_spi_ops,
+       .of_to_plat = mcr3000_spi_gpio_ofdata_to_platdata,
+       .plat_auto = sizeof(struct mcr3000_spi_gpio_plat),
+       .of_match = mcr3000_spi_gpio_ids,
+       .probe  = mcr3000_spi_gpio_probe,
+       .priv_auto = sizeof(struct mcr3000_spi_gpio_data),
+};
diff --git a/configs/MCR3000_defconfig b/configs/MCR3000_defconfig
index 8a88fb445c..ce34c2aa88 100644
--- a/configs/MCR3000_defconfig
+++ b/configs/MCR3000_defconfig
@@ -2,6 +2,7 @@ CONFIG_PPC=y
 CONFIG_TEXT_BASE=0x4000000
 CONFIG_ENV_SIZE=0x2000
 CONFIG_ENV_SECT_SIZE=0x2000
+CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="mcr3000"
 CONFIG_SYS_MONITOR_LEN=327680
 CONFIG_SYS_CLK_FREQ=132000000
@@ -91,6 +92,7 @@ CONFIG_SYS_OR6_PRELIM=0xFFFF0908
 CONFIG_SYS_BR7_PRELIM_BOOL=y
 CONFIG_SYS_BR7_PRELIM=0x1C000001
 CONFIG_SYS_OR7_PRELIM=0xFFFF810A
+CONFIG_MPC8XX_GPIO=y
 # CONFIG_MMC is not set
 CONFIG_MTD=y
 CONFIG_DM_MTD=y
@@ -102,6 +104,9 @@ CONFIG_SYS_MAX_FLASH_SECT=35
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MPC8XX_FEC=y
 CONFIG_DM_SERIAL=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_MPC8XX_SPI=y
 CONFIG_WDT=y
 CONFIG_WDT_MPC8xxx_BME=y
 CONFIG_LZMA=y
-- 
2.43.0

Reply via email to