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