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