board: cssi: Add support for SPI bus on MCR3000 board
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.leroy@csgroup.eu>
diff --git a/arch/powerpc/dts/mcr3000.dts b/arch/powerpc/dts/mcr3000.dts
index c4d7737..edcd835 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 7803016..846fd68 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 8857c9e..537d7fa 100644
--- a/board/cssi/mcr3000/mcr3000.c
+++ b/board/cssi/mcr3000/mcr3000.c
@@ -116,6 +116,11 @@
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 0000000..2bba14e
--- /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.leroy@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 8a88fb4..ce34c2a 100644
--- a/configs/MCR3000_defconfig
+++ b/configs/MCR3000_defconfig
@@ -2,6 +2,7 @@
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_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_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