mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-01 00:54:15 +08:00
Merge series "spi/HiSilicon v3xx: Support dual and quad mode through DMI quirks" from John Garry <john.garry@huawei.com>:
As discussed during the original HiSilicon v3xx SPI driver upstreaming, currently there is no method for the ACPI SPI Serial Bus Connection Resource Descriptor to define the data buswidth [0], [1]. So we can look to get the ACPI spec updated for this, and I have submitted a proposal for a new feature here: https://bugzilla.tianocore.org/show_bug.cgi?id=2557 However I am not sure how successful that will be. In the meantime, as an alternate approach, this RFC proposes to allow the SPI controller driver override the device buswidth. In this example, the driver uses DMI quirks to discover the host machine and set the buswidth override accordingly when the machine is known to support dual or quad mode of operation. I also have included a fix for dual and quad modes in the driver. Comments welcome. thanks. [0] https://lore.kernel.org/linux-mtd/20200109212842.GK3702@sirena.org.uk/ [1] https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf, 19.6.126 John Garry (3): spi: Allow SPI controller override device buswidth spi: HiSilicon v3xx: Properly set CMD_CONFIG for Dual/Quad modes spi: HiSilicon v3xx: Use DMI quirk to set controller buswidth override bits drivers/spi/spi-hisi-sfc-v3xx.c | 99 ++++++++++++++++++++++++++++++++- drivers/spi/spi.c | 4 +- include/linux/spi/spi.h | 3 + 3 files changed, 104 insertions(+), 2 deletions(-) -- 2.17.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/
This commit is contained in:
commit
6c4a3372f0
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -17,6 +18,12 @@
|
||||
#define HISI_SFC_V3XX_VERSION (0x1f8)
|
||||
|
||||
#define HISI_SFC_V3XX_CMD_CFG (0x300)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_FULL_DIO (3 << 17)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT (5 << 17)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_QUAD_IO (6 << 17)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_FULL_QIO (7 << 17)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9
|
||||
#define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8)
|
||||
#define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7)
|
||||
@ -161,6 +168,43 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
|
||||
if (op->addr.nbytes)
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK;
|
||||
|
||||
switch (op->data.buswidth) {
|
||||
case 0 ... 1:
|
||||
break;
|
||||
case 2:
|
||||
if (op->addr.buswidth <= 1) {
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT;
|
||||
} else if (op->addr.buswidth == 2) {
|
||||
if (op->cmd.buswidth <= 1) {
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IO;
|
||||
} else if (op->cmd.buswidth == 2) {
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_FULL_DIO;
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (op->addr.buswidth <= 1) {
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT;
|
||||
} else if (op->addr.buswidth == 4) {
|
||||
if (op->cmd.buswidth <= 1) {
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IO;
|
||||
} else if (op->cmd.buswidth == 4) {
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_FULL_QIO;
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (op->data.dir != SPI_MEM_NO_DATA) {
|
||||
config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF;
|
||||
config |= HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK;
|
||||
@ -207,6 +251,44 @@ static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = {
|
||||
.exec_op = hisi_sfc_v3xx_exec_op,
|
||||
};
|
||||
|
||||
static int hisi_sfc_v3xx_buswidth_override_bits;
|
||||
|
||||
/*
|
||||
* ACPI FW does not allow us to currently set the device buswidth, so quirk it
|
||||
* depending on the board.
|
||||
*/
|
||||
static int __init hisi_sfc_v3xx_dmi_quirk(const struct dmi_system_id *d)
|
||||
{
|
||||
hisi_sfc_v3xx_buswidth_override_bits = SPI_RX_QUAD | SPI_TX_QUAD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id hisi_sfc_v3xx_dmi_quirk_table[] = {
|
||||
{
|
||||
.callback = hisi_sfc_v3xx_dmi_quirk,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "D06"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = hisi_sfc_v3xx_dmi_quirk,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 2280 V2"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = hisi_sfc_v3xx_dmi_quirk,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 200 (Model 2280)"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -222,6 +304,8 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
|
||||
ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
|
||||
SPI_TX_DUAL | SPI_TX_QUAD;
|
||||
|
||||
ctlr->buswidth_override_bits = hisi_sfc_v3xx_buswidth_override_bits;
|
||||
|
||||
host = spi_controller_get_devdata(ctlr);
|
||||
host->dev = dev;
|
||||
|
||||
@ -277,7 +361,20 @@ static struct platform_driver hisi_sfc_v3xx_spi_driver = {
|
||||
.probe = hisi_sfc_v3xx_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(hisi_sfc_v3xx_spi_driver);
|
||||
static int __init hisi_sfc_v3xx_spi_init(void)
|
||||
{
|
||||
dmi_check_system(hisi_sfc_v3xx_dmi_quirk_table);
|
||||
|
||||
return platform_driver_register(&hisi_sfc_v3xx_spi_driver);
|
||||
}
|
||||
|
||||
static void __exit hisi_sfc_v3xx_spi_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&hisi_sfc_v3xx_spi_driver);
|
||||
}
|
||||
|
||||
module_init(hisi_sfc_v3xx_spi_init);
|
||||
module_exit(hisi_sfc_v3xx_spi_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
|
||||
|
@ -510,6 +510,7 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr)
|
||||
spi->dev.bus = &spi_bus_type;
|
||||
spi->dev.release = spidev_release;
|
||||
spi->cs_gpio = -ENOENT;
|
||||
spi->mode = ctlr->buswidth_override_bits;
|
||||
|
||||
spin_lock_init(&spi->statistics.lock);
|
||||
|
||||
@ -2181,9 +2182,10 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
|
||||
return AE_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
ACPI_COMPANION_SET(&spi->dev, adev);
|
||||
spi->max_speed_hz = lookup.max_speed_hz;
|
||||
spi->mode = lookup.mode;
|
||||
spi->mode |= lookup.mode;
|
||||
spi->irq = lookup.irq;
|
||||
spi->bits_per_word = lookup.bits_per_word;
|
||||
spi->chip_select = lookup.chip_select;
|
||||
|
@ -481,6 +481,9 @@ struct spi_controller {
|
||||
/* spi_device.mode flags understood by this controller driver */
|
||||
u32 mode_bits;
|
||||
|
||||
/* spi_device.mode flags override flags for this controller */
|
||||
u32 buswidth_override_bits;
|
||||
|
||||
/* bitmask of supported bits_per_word for transfers */
|
||||
u32 bits_per_word_mask;
|
||||
#define SPI_BPW_MASK(bits) BIT((bits) - 1)
|
||||
|
Loading…
Reference in New Issue
Block a user