In i915-spi, there is no access to the spi controller, all the information has to be extracted form the descriptor region. Cc: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx> Cc: Lucas De Marchi <lucas.demarchi@xxxxxxxxx> Signed-off-by: Tomas Winkler <tomas.winkler@xxxxxxxxx> --- drivers/gpu/drm/i915/spi/intel_spi_drv.c | 190 +++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/drivers/gpu/drm/i915/spi/intel_spi_drv.c b/drivers/gpu/drm/i915/spi/intel_spi_drv.c index 23261f35b71f..a1e7171d05db 100644 --- a/drivers/gpu/drm/i915/spi/intel_spi_drv.c +++ b/drivers/gpu/drm/i915/spi/intel_spi_drv.c @@ -16,14 +16,197 @@ struct i915_spi { void __iomem *base; size_t size; unsigned int nregions; + u32 access_map; struct { const char *name; u8 id; u64 offset; u64 size; + unsigned int is_readable:1; + unsigned int is_writable:1; } regions[]; }; +#define SPI_TRIGGER_REG 0x00000000 +#define SPI_VALSIG_REG 0x00000010 +#define SPI_ADDRESS_REG 0x00000040 +#define SPI_REGION_ID_REG 0x00000044 +/* + * [15:0]-Erase size = 0x0010 4K 0x0080 32K 0x0100 64K + * [23:16]-Reserved + * [31:24]-Erase SPI RegionID + */ +#define SPI_ERASE_REG 0x00000048 +#define SPI_ACCESS_ERROR_REG 0x00000070 +#define SPI_ADDRESS_ERROR_REG 0x00000074 + +/* Flash Valid Signature */ +#define SPI_FLVALSIG 0x0FF0A55A + +#define SPI_MAP_ADDR_MASK 0x000000FF +#define SPI_MAP_ADDR_SHIFT 0x00000004 + +#define REGION_ID_DESCRIPTOR 0 +/* Flash Region Base Address */ +#define FRBA 0x40 +/* Flash Region __n - Flash Descriptor Record */ +#define FLREG(__n) (FRBA + ((__n) * 4)) +/* Flash Map 1 Register */ +#define FLMAP1_REG 0x18 +#define FLMSTR4_OFFSET 0x00C + +#define SPI_ACCESS_ERROR_PCIE_MASK 0x7 + +static inline void spi_set_region_id(struct i915_spi *spi, u8 region) +{ + iowrite32((u32)region, spi->base + SPI_REGION_ID_REG); +} + +static inline u32 spi_error(struct i915_spi *spi) +{ + u32 reg = ioread32(spi->base + SPI_ACCESS_ERROR_REG) & + SPI_ACCESS_ERROR_PCIE_MASK; + + /* reset error bits */ + if (reg) + iowrite32(reg, spi->base + SPI_ACCESS_ERROR_REG); + + return reg; +} + +static inline u32 spi_read32(struct i915_spi *spi, u32 address) +{ + void __iomem *base = spi->base; + + iowrite32(address, base + SPI_ADDRESS_REG); + + return ioread32(base + SPI_TRIGGER_REG); +} + +static int spi_get_access_map(struct i915_spi *spi) +{ + u32 flmap1; + u32 fmba; + u32 fmstr4; + u32 fmstr4_addr; + + spi_set_region_id(spi, REGION_ID_DESCRIPTOR); + + flmap1 = spi_read32(spi, FLMAP1_REG); + if (spi_error(spi)) + return -EIO; + /* Get Flash Master Baser Address (FMBA) */ + fmba = ((flmap1 & SPI_MAP_ADDR_MASK) << SPI_MAP_ADDR_SHIFT); + fmstr4_addr = fmba + FLMSTR4_OFFSET; + + fmstr4 = spi_read32(spi, fmstr4_addr); + if (spi_error(spi)) + return -EIO; + + spi->access_map = fmstr4; + return 0; +} + +static bool spi_region_readable(struct i915_spi *spi, u8 region) +{ + if (region < 12) + return spi->access_map & (1 << (region + 8)); /* [19:8] */ + else + return spi->access_map & (1 << (region - 12)); /* [3:0] */ +} + +static bool spi_region_writeable(struct i915_spi *spi, u8 region) +{ + if (region < 12) + return spi->access_map & (1 << (region + 20)); /* [31:20] */ + else + return spi->access_map & (1 << (region - 8)); /* [7:4] */ +} + +static int i915_spi_is_valid(struct i915_spi *spi) +{ + u32 is_valid; + + spi_set_region_id(spi, REGION_ID_DESCRIPTOR); + + is_valid = spi_read32(spi, SPI_VALSIG_REG); + if (spi_error(spi)) + return -EIO; + + if (is_valid != SPI_FLVALSIG) + return -ENODEV; + + return 0; +} + +static int i915_spi_init(struct i915_spi *spi, struct device *device) +{ + int ret; + unsigned int i, n; + + /* clean error register, previous errors are ignored */ + spi_error(spi); + + ret = i915_spi_is_valid(spi); + if (ret) { + dev_err(device, "The SPI is not valid %d\n", ret); + return ret; + } + + if (spi_get_access_map(spi)) + return -EIO; + + for (i = 0, n = 0; i < spi->nregions; i++) { + u32 address, base, limit, region; + u8 id = spi->regions[i].id; + + address = FLREG(id); + region = spi_read32(spi, address); + + base = (region & 0x0000FFFF) << 12; + limit = (((region & 0xFFFF0000) >> 16) << 12) | 0xFFF; + + dev_dbg(device, "[%d] %s: region: 0x%08X base: 0x%08x limit: 0x%08x\n", + id, spi->regions[i].name, region, base, limit); + + if (base >= limit || (i > 0 && limit == 0)) { + dev_dbg(device, "[%d] %s: disabled\n", + id, spi->regions[i].name); + spi->regions[i].is_readable = 0; + continue; + } + + if (spi->size < limit) + spi->size = limit; + + spi->regions[i].offset = base; + spi->regions[i].size = limit - base + 1; + /* No write access to descriptor; mask it out*/ + spi->regions[i].is_writable = spi_region_writeable(spi, id); + + spi->regions[i].is_readable = spi_region_readable(spi, id); + dev_dbg(device, "Registered, %s id=%d offset=%lld size=%lld rd=%d wr=%d\n", + spi->regions[i].name, + spi->regions[i].id, + spi->regions[i].offset, + spi->regions[i].size, + spi->regions[i].is_readable, + spi->regions[i].is_writable); + + if (spi->regions[i].is_readable) + n++; + } + + dev_dbg(device, "Registered %d regions\n", n); + + /* Need to add 1 to the amount of memory + * so it is reported as an even block + */ + spi->size += 1; + + return n; +} + static int i915_spi_probe(struct platform_device *platdev) { struct resource *bar; @@ -35,6 +218,7 @@ static int i915_spi_probe(struct platform_device *platdev) size_t size; char *name; size_t name_size; + int ret; device = &platdev->dev; @@ -86,6 +270,12 @@ static int i915_spi_probe(struct platform_device *platdev) return PTR_ERR(spi->base); } + ret = i915_spi_init(spi, device); + if (ret < 0) { + dev_err(device, "cannot initialize spi\n"); + return -ENODEV; + } + platform_set_drvdata(platdev, spi); dev_dbg(device, "i915-spi is bound\n"); -- 2.26.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx