^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Octeon Bootbus flash setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2007, 2008 Cavium Networks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/semaphore.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mtd/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/octeon/octeon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static struct map_info flash_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static struct mtd_info *mymtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static const char *part_probe_types[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) "cmdlinepart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #ifdef CONFIG_MTD_REDBOOT_PARTS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) "RedBoot",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static map_word octeon_flash_map_read(struct map_info *map, unsigned long ofs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) map_word r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) down(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) r = inline_map_read(map, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) up(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static void octeon_flash_map_write(struct map_info *map, const map_word datum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned long ofs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) down(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) inline_map_write(map, datum, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) up(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static void octeon_flash_map_copy_from(struct map_info *map, void *to,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned long from, ssize_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) down(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) inline_map_copy_from(map, to, from, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) up(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static void octeon_flash_map_copy_to(struct map_info *map, unsigned long to,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) const void *from, ssize_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) down(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) inline_map_copy_to(map, to, from, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) up(&octeon_bootbus_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Module/ driver initialization.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * Returns Zero on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int octeon_flash_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) union cvmx_mio_boot_reg_cfgx region_cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) u32 cs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) r = of_property_read_u32(np, "reg", &cs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Read the bootbus region 0 setup to determine the base
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * address of the flash.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) region_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (region_cfg.s.en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * The bootloader always takes the flash and sets its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * address so the entire flash fits below
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * 0x1fc00000. This way the flash aliases to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * 0x1fc00000 for booting. Software can access the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * full flash at the true address, while core boot can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * access 4MB.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* Use this name so old part lines work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) flash_map.name = "phys_mapped_flash";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) flash_map.phys = region_cfg.s.base << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) flash_map.size = 0x1fc00000 - flash_map.phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* 8-bit bus (0 + 1) or 16-bit bus (1 + 1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) flash_map.bankwidth = region_cfg.s.width + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) flash_map.virt = ioremap(flash_map.phys, flash_map.size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) pr_notice("Bootbus flash: Setting flash for %luMB flash at "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) "0x%08llx\n", flash_map.size >> 20, flash_map.phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) WARN_ON(!map_bankwidth_supported(flash_map.bankwidth));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) flash_map.read = octeon_flash_map_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) flash_map.write = octeon_flash_map_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) flash_map.copy_from = octeon_flash_map_copy_from;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) flash_map.copy_to = octeon_flash_map_copy_to;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) mymtd = do_map_probe("cfi_probe", &flash_map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (mymtd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) mymtd->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) mtd_device_parse_register(mymtd, part_probe_types,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) NULL, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) pr_err("Failed to register MTD device for flash\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static const struct of_device_id of_flash_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .compatible = "cfi-flash",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) MODULE_DEVICE_TABLE(of, of_flash_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static struct platform_driver of_flash_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .name = "octeon-of-flash",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .of_match_table = of_flash_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .probe = octeon_flash_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static int octeon_flash_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return platform_driver_register(&of_flash_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) late_initcall(octeon_flash_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) MODULE_LICENSE("GPL");