321 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Copyright (C) 2022 Hewlett-Packard Development Company, L.P. */3 4#include <linux/iopoll.h>5#include <linux/of.h>6#include <linux/platform_device.h>7#include <linux/spi/spi.h>8#include <linux/spi/spi-mem.h>9 10#define GXP_SPI0_MAX_CHIPSELECT 211#define GXP_SPI_SLEEP_TIME 112#define GXP_SPI_TIMEOUT (130 * 1000000 / GXP_SPI_SLEEP_TIME)13 14#define MANUAL_MODE 015#define DIRECT_MODE 116#define SPILDAT_LEN 25617 18#define OFFSET_SPIMCFG 0x019#define OFFSET_SPIMCTRL 0x420#define OFFSET_SPICMD 0x521#define OFFSET_SPIDCNT 0x622#define OFFSET_SPIADDR 0x823#define OFFSET_SPIINTSTS 0xc24 25#define SPIMCTRL_START 0x0126#define SPIMCTRL_BUSY 0x0227#define SPIMCTRL_DIR 0x0828 29struct gxp_spi;30 31struct gxp_spi_chip {32 struct gxp_spi *spifi;33 u32 cs;34};35 36struct gxp_spi_data {37 u32 max_cs;38 u32 mode_bits;39};40 41struct gxp_spi {42 const struct gxp_spi_data *data;43 void __iomem *reg_base;44 void __iomem *dat_base;45 void __iomem *dir_base;46 struct device *dev;47 struct gxp_spi_chip chips[GXP_SPI0_MAX_CHIPSELECT];48};49 50static void gxp_spi_set_mode(struct gxp_spi *spifi, int mode)51{52 u8 value;53 void __iomem *reg_base = spifi->reg_base;54 55 value = readb(reg_base + OFFSET_SPIMCTRL);56 57 if (mode == MANUAL_MODE) {58 writeb(0x55, reg_base + OFFSET_SPICMD);59 writeb(0xaa, reg_base + OFFSET_SPICMD);60 value &= ~0x30;61 } else {62 value |= 0x30;63 }64 writeb(value, reg_base + OFFSET_SPIMCTRL);65}66 67static int gxp_spi_read_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)68{69 int ret;70 struct gxp_spi *spifi = chip->spifi;71 void __iomem *reg_base = spifi->reg_base;72 u32 value;73 74 value = readl(reg_base + OFFSET_SPIMCFG);75 value &= ~(1 << 24);76 value |= (chip->cs << 24);77 value &= ~(0x07 << 16);78 value &= ~(0x1f << 19);79 writel(value, reg_base + OFFSET_SPIMCFG);80 81 writel(0, reg_base + OFFSET_SPIADDR);82 83 writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);84 85 writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);86 87 value = readb(reg_base + OFFSET_SPIMCTRL);88 value &= ~SPIMCTRL_DIR;89 value |= SPIMCTRL_START;90 91 writeb(value, reg_base + OFFSET_SPIMCTRL);92 93 ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,94 !(value & SPIMCTRL_BUSY),95 GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);96 if (ret) {97 dev_warn(spifi->dev, "read reg busy time out\n");98 return ret;99 }100 101 memcpy_fromio(op->data.buf.in, spifi->dat_base, op->data.nbytes);102 return ret;103}104 105static int gxp_spi_write_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)106{107 int ret;108 struct gxp_spi *spifi = chip->spifi;109 void __iomem *reg_base = spifi->reg_base;110 u32 value;111 112 value = readl(reg_base + OFFSET_SPIMCFG);113 value &= ~(1 << 24);114 value |= (chip->cs << 24);115 value &= ~(0x07 << 16);116 value &= ~(0x1f << 19);117 writel(value, reg_base + OFFSET_SPIMCFG);118 119 writel(0, reg_base + OFFSET_SPIADDR);120 121 writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);122 123 memcpy_toio(spifi->dat_base, op->data.buf.in, op->data.nbytes);124 125 writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);126 127 value = readb(reg_base + OFFSET_SPIMCTRL);128 value |= SPIMCTRL_DIR;129 value |= SPIMCTRL_START;130 131 writeb(value, reg_base + OFFSET_SPIMCTRL);132 133 ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,134 !(value & SPIMCTRL_BUSY),135 GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);136 if (ret)137 dev_warn(spifi->dev, "write reg busy time out\n");138 139 return ret;140}141 142static ssize_t gxp_spi_read(struct gxp_spi_chip *chip, const struct spi_mem_op *op)143{144 struct gxp_spi *spifi = chip->spifi;145 u32 offset = op->addr.val;146 147 if (chip->cs == 0)148 offset += 0x4000000;149 150 memcpy_fromio(op->data.buf.in, spifi->dir_base + offset, op->data.nbytes);151 152 return 0;153}154 155static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op *op)156{157 struct gxp_spi *spifi = chip->spifi;158 void __iomem *reg_base = spifi->reg_base;159 u32 write_len;160 u32 value;161 int ret;162 163 write_len = op->data.nbytes;164 if (write_len > SPILDAT_LEN)165 write_len = SPILDAT_LEN;166 167 value = readl(reg_base + OFFSET_SPIMCFG);168 value &= ~(1 << 24);169 value |= (chip->cs << 24);170 value &= ~(0x07 << 16);171 value |= (op->addr.nbytes << 16);172 value &= ~(0x1f << 19);173 writel(value, reg_base + OFFSET_SPIMCFG);174 175 writel(op->addr.val, reg_base + OFFSET_SPIADDR);176 177 writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);178 179 writew(write_len, reg_base + OFFSET_SPIDCNT);180 181 memcpy_toio(spifi->dat_base, op->data.buf.in, write_len);182 183 value = readb(reg_base + OFFSET_SPIMCTRL);184 value |= SPIMCTRL_DIR;185 value |= SPIMCTRL_START;186 187 writeb(value, reg_base + OFFSET_SPIMCTRL);188 189 ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,190 !(value & SPIMCTRL_BUSY),191 GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);192 if (ret) {193 dev_warn(spifi->dev, "write busy time out\n");194 return ret;195 }196 197 return 0;198}199 200static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)201{202 struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->controller);203 struct gxp_spi_chip *chip = &spifi->chips[spi_get_chipselect(mem->spi, 0)];204 int ret;205 206 if (op->data.dir == SPI_MEM_DATA_IN) {207 if (!op->addr.nbytes)208 ret = gxp_spi_read_reg(chip, op);209 else210 ret = gxp_spi_read(chip, op);211 } else {212 if (!op->addr.nbytes)213 ret = gxp_spi_write_reg(chip, op);214 else215 ret = gxp_spi_write(chip, op);216 }217 218 return ret;219}220 221static int gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)222{223 int ret;224 225 ret = do_gxp_exec_mem_op(mem, op);226 if (ret)227 dev_err(&mem->spi->dev, "operation failed: %d", ret);228 229 return ret;230}231 232static const struct spi_controller_mem_ops gxp_spi_mem_ops = {233 .exec_op = gxp_exec_mem_op,234};235 236static int gxp_spi_setup(struct spi_device *spi)237{238 struct gxp_spi *spifi = spi_controller_get_devdata(spi->controller);239 unsigned int cs = spi_get_chipselect(spi, 0);240 struct gxp_spi_chip *chip = &spifi->chips[cs];241 242 chip->spifi = spifi;243 chip->cs = cs;244 245 gxp_spi_set_mode(spifi, MANUAL_MODE);246 247 return 0;248}249 250static int gxp_spifi_probe(struct platform_device *pdev)251{252 struct device *dev = &pdev->dev;253 const struct gxp_spi_data *data;254 struct spi_controller *ctlr;255 struct gxp_spi *spifi;256 int ret;257 258 data = of_device_get_match_data(&pdev->dev);259 260 ctlr = devm_spi_alloc_host(dev, sizeof(*spifi));261 if (!ctlr)262 return -ENOMEM;263 264 spifi = spi_controller_get_devdata(ctlr);265 266 platform_set_drvdata(pdev, spifi);267 spifi->data = data;268 spifi->dev = dev;269 270 spifi->reg_base = devm_platform_ioremap_resource(pdev, 0);271 if (IS_ERR(spifi->reg_base))272 return PTR_ERR(spifi->reg_base);273 274 spifi->dat_base = devm_platform_ioremap_resource(pdev, 1);275 if (IS_ERR(spifi->dat_base))276 return PTR_ERR(spifi->dat_base);277 278 spifi->dir_base = devm_platform_ioremap_resource(pdev, 2);279 if (IS_ERR(spifi->dir_base))280 return PTR_ERR(spifi->dir_base);281 282 ctlr->mode_bits = data->mode_bits;283 ctlr->bus_num = pdev->id;284 ctlr->mem_ops = &gxp_spi_mem_ops;285 ctlr->setup = gxp_spi_setup;286 ctlr->num_chipselect = data->max_cs;287 ctlr->dev.of_node = dev->of_node;288 289 ret = devm_spi_register_controller(dev, ctlr);290 if (ret) {291 return dev_err_probe(&pdev->dev, ret,292 "failed to register spi controller\n");293 }294 295 return 0;296}297 298static const struct gxp_spi_data gxp_spifi_data = {299 .max_cs = 2,300 .mode_bits = 0,301};302 303static const struct of_device_id gxp_spifi_match[] = {304 {.compatible = "hpe,gxp-spifi", .data = &gxp_spifi_data },305 { /* null */ }306};307MODULE_DEVICE_TABLE(of, gxp_spifi_match);308 309static struct platform_driver gxp_spifi_driver = {310 .probe = gxp_spifi_probe,311 .driver = {312 .name = "gxp-spifi",313 .of_match_table = gxp_spifi_match,314 },315};316module_platform_driver(gxp_spifi_driver);317 318MODULE_DESCRIPTION("HPE GXP SPI Flash Interface driver");319MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");320MODULE_LICENSE("GPL");321