Browse Source

sf: Enable FDT-based configuration and memory mapping

Enable device tree control of SPI flash, and use this to implement
memory-mapped SPI flash, which is supported on Intel chips.

Signed-off-by: Simon Glass <sjg@chromium.org>
Simon Glass 12 năm trước cách đây
mục cha
commit
bb8215f437
4 tập tin đã thay đổi với 48 bổ sung1 xóa
  1. 45 1
      drivers/mtd/spi/spi_flash.c
  2. 1 0
      include/fdtdec.h
  3. 1 0
      include/spi_flash.h
  4. 1 0
      lib/fdtdec.c

+ 45 - 1
drivers/mtd/spi/spi_flash.c

@@ -8,6 +8,7 @@
  */
 
 #include <common.h>
+#include <fdtdec.h>
 #include <malloc.h>
 #include <spi.h>
 #include <spi_flash.h>
@@ -15,6 +16,8 @@
 
 #include "spi_flash_internal.h"
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static void spi_flash_addr(u32 addr, u8 *cmd)
 {
 	/* cmd[0] is actual command */
@@ -146,6 +149,10 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
 {
 	u8 cmd[5];
 
+	/* Handle memory-mapped SPI */
+	if (flash->memory_map)
+		memcpy(data, flash->memory_map + offset, len);
+
 	cmd[0] = CMD_READ_ARRAY_FAST;
 	spi_flash_addr(offset, cmd);
 	cmd[4] = 0x00;
@@ -275,6 +282,34 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
 	return 0;
 }
 
+#ifdef CONFIG_OF_CONTROL
+int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
+{
+	fdt_addr_t addr;
+	fdt_size_t size;
+	int node;
+
+	/* If there is no node, do nothing */
+	node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
+	if (node < 0)
+		return 0;
+
+	addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
+	if (addr == FDT_ADDR_T_NONE) {
+		debug("%s: Cannot decode address\n", __func__);
+		return 0;
+	}
+
+	if (flash->size != size) {
+		debug("%s: Memory map must cover entire device\n", __func__);
+		return -1;
+	}
+	flash->memory_map = (void *)addr;
+
+	return 0;
+}
+#endif /* CONFIG_OF_CONTROL */
+
 /*
  * The following table holds all device probe functions
  *
@@ -391,9 +426,18 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 		goto err_manufacturer_probe;
 	}
 
+#ifdef CONFIG_OF_CONTROL
+	if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {
+		debug("SF: FDT decode error\n");
+		goto err_manufacturer_probe;
+	}
+#endif
 	printf("SF: Detected %s with page size ", flash->name);
 	print_size(flash->sector_size, ", total ");
-	print_size(flash->size, "\n");
+	print_size(flash->size, "");
+	if (flash->memory_map)
+		printf(", mapped at %p", flash->memory_map);
+	puts("\n");
 
 	spi_release_bus(spi);
 

+ 1 - 0
include/fdtdec.h

@@ -86,6 +86,7 @@ enum fdt_compat_id {
 	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */
 	COMPAT_SAMSUNG_EXYNOS_USB_PHY,	/* Exynos phy controller for usb2.0 */
 	COMPAT_MAXIM_MAX77686_PMIC,	/* MAX77686 PMIC */
+	COMPAT_GENERIC_SPI_FLASH,	/* Generic SPI Flash chip */
 
 	COMPAT_COUNT,
 };

+ 1 - 0
include/spi_flash.h

@@ -39,6 +39,7 @@ struct spi_flash {
 	/* Erase (sector) size */
 	u32		sector_size;
 
+	void *memory_map;	/* Address of read-only SPI flash access */
 	int		(*read)(struct spi_flash *flash, u32 offset,
 				size_t len, void *buf);
 	int		(*write)(struct spi_flash *flash, u32 offset,

+ 1 - 0
lib/fdtdec.c

@@ -59,6 +59,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
 	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
 	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
+	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
 };
 
 const char *fdtdec_get_compatible(enum fdt_compat_id id)