From 8f58ecf6c328b318187027e1a911a975747b173d Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 2 Apr 2024 19:20:07 +0200 Subject: spi: mpc8xx: Add GPIO dependency Since commit 773ad4ebb1d6 ("spi, mpc8xx: Add support for chipselect via GPIO and fixups"), DM_GPIO is required for 8xx SPI. Add the missing dependency to avoid build failures. Fixes: 773ad4ebb1d6 ("spi, mpc8xx: Add support for chipselect via GPIO and fixups") Signed-off-by: Christophe Leroy --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 69b184b0d9e..612434633b3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -262,7 +262,7 @@ config MESON_SPIFC_A1 config MPC8XX_SPI bool "MPC8XX SPI Driver" - depends on MPC8xx + depends on MPC8xx && DM_GPIO help Enable support for SPI on MPC8XX -- cgit v1.3.1 From ea208201a12913e7a5b7b4b38624942effa44c05 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 9 Apr 2024 08:38:08 +0200 Subject: spi: mpc8xx: Fix transfert when input or output buffer is NULL xfer ops can be passed a NULL input or output buffer. At the time being the driver ignores it and overwrites memory at 0. Define a dummy buffer and use it when either input or output buffer is NULL. Bail out when both are NULL as it shouldn't. Also increase MAX_BUFFER len to 32k as the current is pretty low. Signed-off-by: Christophe Leroy --- drivers/spi/mpc8xx_spi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c index 5c8d7609351..2aa9c7d5df9 100644 --- a/drivers/spi/mpc8xx_spi.c +++ b/drivers/spi/mpc8xx_spi.c @@ -29,7 +29,7 @@ #define CPM_SPI_BASE_RX CPM_SPI_BASE #define CPM_SPI_BASE_TX (CPM_SPI_BASE + sizeof(cbd_t)) -#define MAX_BUFFER 0x104 +#define MAX_BUFFER 0x8000 /* Max possible is 0xffff. We want power of 2 */ struct mpc8xx_priv { spi_t __iomem *spi; @@ -37,6 +37,8 @@ struct mpc8xx_priv { int max_cs; }; +static char dummy_buffer[MAX_BUFFER]; + static int mpc8xx_spi_set_mode(struct udevice *dev, uint mod) { return 0; @@ -154,6 +156,8 @@ static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen, int tm; size_t count = (bitlen + 7) / 8; + if (!din && !dout) + return -EINVAL; if (count > MAX_BUFFER) return -EINVAL; @@ -165,12 +169,12 @@ static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen, mpc8xx_spi_cs_activate(dev); /* Setting tx bd status and data length */ - out_be32(&tbdf->cbd_bufaddr, (ulong)dout); + out_be32(&tbdf->cbd_bufaddr, dout ? (ulong)dout : (ulong)dummy_buffer); out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP); out_be16(&tbdf->cbd_datlen, count); /* Setting rx bd status and data length */ - out_be32(&rbdf->cbd_bufaddr, (ulong)din); + out_be32(&rbdf->cbd_bufaddr, din ? (ulong)din : (ulong)dummy_buffer); out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP); out_be16(&rbdf->cbd_datlen, 0); /* rx length has no significance */ -- cgit v1.3.1 From c578728d2e33754e38af869f6cdf992d18d058da Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 2 Apr 2024 18:55:31 +0200 Subject: thermal: Add support for TI LM74 LM74 is a SPI temperature sensor. Implement a driver to read temperature from it. Signed-off-by: Christophe Leroy --- drivers/thermal/Kconfig | 6 ++++++ drivers/thermal/Makefile | 1 + drivers/thermal/ti-lm74.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 drivers/thermal/ti-lm74.c (limited to 'drivers') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 681b621760d..440eb64a566 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -41,4 +41,10 @@ config TI_DRA7_THERMAL Enable thermal support for for the Texas Instruments DRA752 SoC family. The driver supports reading CPU temperature. +config TI_LM74_THERMAL + bool "Temperature sensor driver for TI LM74 chip" + help + Enable thermal support for the Texas Instruments LM74 chip. + The driver supports reading CPU temperature. + endif # if DM_THERMAL diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 8acc7d20cb9..b5ab0fc221f 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o obj-$(CONFIG_IMX_TMU) += imx_tmu.o +obj-$(CONFIG_TI_LM74_THERMAL) += ti-lm74.o diff --git a/drivers/thermal/ti-lm74.c b/drivers/thermal/ti-lm74.c new file mode 100644 index 00000000000..7d56f75df06 --- /dev/null +++ b/drivers/thermal/ti-lm74.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * TI LM74 temperature sensor driver + * + * Copyright (C) 2024 CS GROUP France + * + */ + +#include +#include +#include + +static int ti_lm74_get_temp(struct udevice *dev, int *temp) +{ + char buf[2]; + s16 raw; + int ret; + + ret = dm_spi_claim_bus(dev); + if (ret) + return ret; + + ret = dm_spi_xfer(dev, 16, NULL, buf, SPI_XFER_BEGIN | SPI_XFER_END); + + dm_spi_release_bus(dev); + if (ret) + return ret; + + raw = ((buf[0] << 8) + buf[1]) >> 3; + + *temp = (((int)raw * 125) + 1000) / 2000; + + return 0; +} + +static struct dm_thermal_ops ti_lm74_ops = { + .get_temp = ti_lm74_get_temp, +}; + +static const struct udevice_id of_ti_lm74_match[] = { + { + .compatible = "ti,lm74", + }, + {}, +}; + +U_BOOT_DRIVER(ti_bandgap_thermal) = { + .name = "ti_lm74_thermal", + .id = UCLASS_THERMAL, + .ops = &ti_lm74_ops, + .of_match = of_ti_lm74_match, +}; -- cgit v1.3.1 From dcf7af5fd9af91674ace085663f8b69943a3c61d Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 12 Apr 2024 13:19:47 +0200 Subject: powerpc: 8xx: Set SDMA configuration register correcly SDMA configuration register needs to be set up only once and doesn't belong to drivers. Also, the value to be used is different on mpc885. So do the init in cpu_init_f() with 0x40 for mpc885 and 0x1 for others. Signed-off-by: Christophe Leroy --- arch/powerpc/cpu/mpc8xx/cpu_init.c | 6 ++++++ drivers/spi/mpc8xx_spi.c | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/cpu/mpc8xx/cpu_init.c b/arch/powerpc/cpu/mpc8xx/cpu_init.c index aac4203a6e4..d1abe8f00bf 100644 --- a/arch/powerpc/cpu/mpc8xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc8xx/cpu_init.c @@ -92,6 +92,12 @@ void cpu_init_f(immap_t __iomem *immr) CONFIG_SYS_PLPRCR); #endif + /* Set SDMA configuration register */ + if (IS_ENABLED(CONFIG_MPC885)) + out_be32(&immr->im_siu_conf.sc_sdcr, 0x0040); + else + out_be32(&immr->im_siu_conf.sc_sdcr, 0x0001); + /* * Memory Controller: */ diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c index 2aa9c7d5df9..0d142f12e96 100644 --- a/drivers/spi/mpc8xx_spi.c +++ b/drivers/spi/mpc8xx_spi.c @@ -103,10 +103,6 @@ static int mpc8xx_spi_probe(struct udevice *dev) while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ; -/* 5 */ - /* Set SDMA configuration register */ - out_be32(&immr->im_siu_conf.sc_sdcr, 0x0001); - /* 6 */ /* Set to big endian. */ out_8(&spi->spi_tfcr, SMC_EB); -- cgit v1.3.1 From 244f8461eb270013fe61d17b5029d62fac67e107 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 12 Apr 2024 13:53:57 +0200 Subject: spi: mpc8xx: Allow transfer of more than MAX_BUFFER len Perform multiple transfer of size MAX_BUFFER when the data to be transferred is longer than MAX_BUFFER. Signed-off-by: Christophe Leroy --- drivers/spi/mpc8xx_spi.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c index 0d142f12e96..a193ac711b4 100644 --- a/drivers/spi/mpc8xx_spi.c +++ b/drivers/spi/mpc8xx_spi.c @@ -143,27 +143,17 @@ static void mpc8xx_spi_cs_deactivate(struct udevice *dev) dm_gpio_set_value(&priv->gpios[platdata->cs], 0); } -static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) +static int mpc8xx_spi_xfer_one(struct udevice *dev, size_t count, + const void *dout, void *din) { immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cp = &immr->im_cpm; cbd_t __iomem *tbdf, *rbdf; int tm; - size_t count = (bitlen + 7) / 8; - - if (!din && !dout) - return -EINVAL; - if (count > MAX_BUFFER) - return -EINVAL; tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX]; rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX]; - /* Set CS for device */ - if (flags & SPI_XFER_BEGIN) - mpc8xx_spi_cs_activate(dev); - /* Setting tx bd status and data length */ out_be32(&tbdf->cbd_bufaddr, dout ? (ulong)dout : (ulong)dummy_buffer); out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP); @@ -196,13 +186,43 @@ static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen, } if (tm >= 1000) - printf("*** spi_xfer: Time out while xferring to/from SPI!\n"); + return -ETIMEDOUT; + + return 0; +} +static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + size_t count = (bitlen + 7) / 8; + size_t offset = 0; + int ret = 0; + + if (!din && !dout) + return -EINVAL; + + /* Set CS for device */ + if (flags & SPI_XFER_BEGIN) + mpc8xx_spi_cs_activate(dev); + + while (count > 0 && !ret) { + size_t chunk = min(count, (size_t)MAX_BUFFER); + const void *out = dout ? dout + offset : NULL; + void *in = din ? din + offset : NULL; + + ret = mpc8xx_spi_xfer_one(dev, chunk, out, in); + + offset += chunk; + count -= chunk; + } /* Clear CS for device */ if (flags & SPI_XFER_END) mpc8xx_spi_cs_deactivate(dev); - return 0; + if (ret) + printf("*** spi_xfer: Time out while xferring to/from SPI!\n"); + + return ret; } static int mpc8xx_spi_ofdata_to_platdata(struct udevice *dev) -- cgit v1.3.1 From dff36805c7fca1edabf3a8be94a8431928e3aec8 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 12 Apr 2024 18:16:59 +0200 Subject: spi: mpc8xx: Use 16 bit mode for large transfers with even size On CPM, the RISC core is a lot more efficiant when doing transfers in 16-bits chunks than in 8-bits chunks, but unfortunately the words need to be byte swapped. So, for large tranfers with an even size, allocate a temporary buffer and byte-swap data before and after transfer. This change allows setting higher speed for transfer. For instance on an MPC 8xx (CPM1 comms RISC processor), the documentation tells that transfer in byte mode at 1 kbit/s uses 0.200% of CPM load at 25 MHz while a word transfer at the same speed uses 0.032% of CPM load. This means the speed can be 6 times higher in word mode for the same CPM load. For small transfers, the load reduction is not worth the CPU load required to allocate the temporary buffer, so do it only when data size is over 64 bytes. Signed-off-by: Christophe Leroy --- drivers/spi/mpc8xx_spi.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c index a193ac711b4..b1abfbf4fcf 100644 --- a/drivers/spi/mpc8xx_spi.c +++ b/drivers/spi/mpc8xx_spi.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #define CPM_SPI_BASE_TX (CPM_SPI_BASE + sizeof(cbd_t)) #define MAX_BUFFER 0x8000 /* Max possible is 0xffff. We want power of 2 */ +#define MIN_HWORD_XFER 64 /* Minimum size for 16 bits transfer */ struct mpc8xx_priv { spi_t __iomem *spi; @@ -149,23 +151,46 @@ static int mpc8xx_spi_xfer_one(struct udevice *dev, size_t count, immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cp = &immr->im_cpm; cbd_t __iomem *tbdf, *rbdf; + void *bufout, *bufin; + u16 spmode_len; int tm; tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX]; rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX]; + if (!(count & 1) && count >= MIN_HWORD_XFER) { + spmode_len = SPMODE_LEN(16); + if (dout) { + int i; + + bufout = malloc(count); + for (i = 0; i < count; i += 2) + *(u16 *)(bufout + i) = swab16(*(u16 *)(dout + i)); + } else { + bufout = NULL; + } + if (din) + bufin = malloc(count); + else + bufin = NULL; + } else { + spmode_len = SPMODE_LEN(8); + bufout = (void *)dout; + bufin = din; + } + /* Setting tx bd status and data length */ - out_be32(&tbdf->cbd_bufaddr, dout ? (ulong)dout : (ulong)dummy_buffer); + out_be32(&tbdf->cbd_bufaddr, bufout ? (ulong)bufout : (ulong)dummy_buffer); out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP); out_be16(&tbdf->cbd_datlen, count); /* Setting rx bd status and data length */ - out_be32(&rbdf->cbd_bufaddr, din ? (ulong)din : (ulong)dummy_buffer); + out_be32(&rbdf->cbd_bufaddr, bufin ? (ulong)bufin : (ulong)dummy_buffer); out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP); out_be16(&rbdf->cbd_datlen, 0); /* rx length has no significance */ clrsetbits_be16(&cp->cp_spmode, ~SPMODE_LOOP, SPMODE_REV | SPMODE_MSTR | - SPMODE_EN | SPMODE_LEN(8) | SPMODE_PM(0x8)); + SPMODE_EN | spmode_len | SPMODE_PM(0x8)); out_8(&cp->cp_spim, 0); /* Mask all SPI events */ out_8(&cp->cp_spie, SPI_EMASK); /* Clear all SPI events */ @@ -188,6 +213,19 @@ static int mpc8xx_spi_xfer_one(struct udevice *dev, size_t count, if (tm >= 1000) return -ETIMEDOUT; + if (!(count & 1) && count > MIN_HWORD_XFER) { + if (dout) + free(bufout); + if (din) { + int i; + + bufout = malloc(count); + for (i = 0; i < count; i += 2) + *(u16 *)(din + i) = swab16(*(u16 *)(bufin + i)); + free(bufin); + } + } + return 0; } -- cgit v1.3.1 From 4fb931ed531e7e0a2deb32b392854a118a93ae17 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 12 Apr 2024 19:36:19 +0200 Subject: spi: mpc8xx: Set up speed as requested Set the speed requested through mpc8xx_spi_set_speed() instead of hardcoding a fixed speed. Signed-off-by: Christophe Leroy --- drivers/spi/mpc8xx_spi.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c index b1abfbf4fcf..e1448cc6196 100644 --- a/drivers/spi/mpc8xx_spi.c +++ b/drivers/spi/mpc8xx_spi.c @@ -48,6 +48,21 @@ static int mpc8xx_spi_set_mode(struct udevice *dev, uint mod) static int mpc8xx_spi_set_speed(struct udevice *dev, uint speed) { + immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; + cpm8xx_t __iomem *cp = &immr->im_cpm; + u8 pm = (gd->arch.brg_clk - 1) / (speed * 16); + + if (pm > 16) { + setbits_be16(&cp->cp_spmode, SPMODE_DIV16); + pm /= 16; + if (pm > 16) + pm = 16; + } else { + clrbits_be16(&cp->cp_spmode, SPMODE_DIV16); + } + + clrsetbits_be16(&cp->cp_spmode, SPMODE_PM(0xf), SPMODE_PM(pm)); + return 0; } @@ -189,8 +204,8 @@ static int mpc8xx_spi_xfer_one(struct udevice *dev, size_t count, out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP); out_be16(&rbdf->cbd_datlen, 0); /* rx length has no significance */ - clrsetbits_be16(&cp->cp_spmode, ~SPMODE_LOOP, SPMODE_REV | SPMODE_MSTR | - SPMODE_EN | spmode_len | SPMODE_PM(0x8)); + clrsetbits_be16(&cp->cp_spmode, ~(SPMODE_LOOP | SPMODE_PM(0xf) | SPMODE_DIV16), + SPMODE_REV | SPMODE_MSTR | SPMODE_EN | spmode_len); out_8(&cp->cp_spim, 0); /* Mask all SPI events */ out_8(&cp->cp_spie, SPI_EMASK); /* Clear all SPI events */ -- cgit v1.3.1