]>
Commit | Line | Data |
---|---|---|
2d18ef23 MP |
1 | /* |
2 | * (C) Copyright 2015 | |
5be93569 | 3 | * Kamil Lulko, <kamil.lulko@gmail.com> |
2d18ef23 MP |
4 | * |
5 | * Copyright 2015 ATS Advanced Telematics Systems GmbH | |
6 | * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com> | |
7 | * | |
8 | * SPDX-License-Identifier: GPL-2.0+ | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
12 | #include <asm/io.h> | |
13 | #include <asm/arch/stm32.h> | |
14 | ||
15 | #define STM32_FLASH_KEY1 0x45670123 | |
16 | #define STM32_FLASH_KEY2 0xcdef89ab | |
17 | ||
18 | #define STM32_NUM_BANKS 2 | |
19 | #define STM32_MAX_BANK 0x200 | |
20 | ||
21 | flash_info_t flash_info[STM32_NUM_BANKS]; | |
22 | static struct stm32_flash_bank_regs *flash_bank[STM32_NUM_BANKS]; | |
23 | ||
24 | static void stm32f1_flash_lock(u8 bank, u8 lock) | |
25 | { | |
26 | if (lock) { | |
27 | setbits_le32(&flash_bank[bank]->cr, STM32_FLASH_CR_LOCK); | |
28 | } else { | |
29 | writel(STM32_FLASH_KEY1, &flash_bank[bank]->keyr); | |
30 | writel(STM32_FLASH_KEY2, &flash_bank[bank]->keyr); | |
31 | } | |
32 | } | |
33 | ||
34 | /* Only XL devices are supported (2 KiB sector size) */ | |
35 | unsigned long flash_init(void) | |
36 | { | |
37 | u8 i, banks; | |
38 | u16 j, size; | |
39 | ||
40 | /* Set up accessors for XL devices with wonky register layout */ | |
41 | flash_bank[0] = (struct stm32_flash_bank_regs *)&STM32_FLASH->keyr; | |
42 | flash_bank[1] = (struct stm32_flash_bank_regs *)&STM32_FLASH->keyr2; | |
43 | ||
44 | /* | |
45 | * Get total flash size (in KiB) and configure number of banks | |
46 | * present and sector count per bank. | |
47 | */ | |
48 | size = readw(&STM32_DES->flash_size); | |
49 | if (size <= STM32_MAX_BANK) { | |
50 | banks = 1; | |
51 | flash_info[0].sector_count = size >> 1; | |
d1fe1976 | 52 | } else { |
2d18ef23 MP |
53 | banks = 2; |
54 | flash_info[0].sector_count = STM32_MAX_BANK >> 1; | |
55 | flash_info[1].sector_count = (size - STM32_MAX_BANK) >> 1; | |
56 | } | |
57 | ||
58 | /* Configure start/size for all sectors */ | |
59 | for (i = 0; i < banks; i++) { | |
60 | flash_info[i].flash_id = FLASH_STM32F1; | |
61 | flash_info[i].start[0] = CONFIG_SYS_FLASH_BASE + (i << 19); | |
62 | flash_info[i].size = 2048; | |
63 | for (j = 1; (j < flash_info[i].sector_count); j++) { | |
64 | flash_info[i].start[j] = flash_info[i].start[j - 1] | |
65 | + 2048; | |
66 | flash_info[i].size += 2048; | |
67 | } | |
68 | } | |
69 | ||
70 | return size << 10; | |
71 | } | |
72 | ||
73 | void flash_print_info(flash_info_t *info) | |
74 | { | |
75 | int i; | |
76 | ||
77 | if (info->flash_id == FLASH_UNKNOWN) { | |
78 | printf("Missing or unknown FLASH type\n"); | |
79 | return; | |
80 | } else if (info->flash_id == FLASH_STM32F1) { | |
81 | printf("STM32F1 Embedded Flash\n"); | |
82 | } | |
83 | ||
84 | printf(" Size: %ld MB in %d Sectors\n", | |
85 | info->size >> 10, info->sector_count); | |
86 | ||
87 | printf(" Sector Start Addresses:"); | |
88 | for (i = 0; i < info->sector_count; ++i) { | |
89 | if ((i % 5) == 0) | |
90 | printf("\n "); | |
91 | printf(" %08lX%s", | |
92 | info->start[i], | |
93 | info->protect[i] ? " (RO)" : " "); | |
94 | } | |
95 | printf("\n"); | |
96 | return; | |
97 | } | |
98 | ||
99 | int flash_erase(flash_info_t *info, int first, int last) | |
100 | { | |
101 | u8 bank = 0xff; | |
102 | int i; | |
103 | ||
104 | for (i = 0; i < STM32_NUM_BANKS; i++) { | |
105 | if (info == &flash_info[i]) { | |
106 | bank = i; | |
107 | break; | |
108 | } | |
109 | } | |
110 | if (bank == 0xff) | |
111 | return -1; | |
112 | ||
113 | stm32f1_flash_lock(bank, 0); | |
114 | ||
115 | for (i = first; i <= last; i++) { | |
116 | while (readl(&flash_bank[bank]->sr) & STM32_FLASH_SR_BSY) | |
117 | ; | |
118 | ||
119 | setbits_le32(&flash_bank[bank]->cr, STM32_FLASH_CR_PER); | |
120 | ||
121 | writel(info->start[i], &flash_bank[bank]->ar); | |
122 | ||
123 | setbits_le32(&flash_bank[bank]->cr, STM32_FLASH_CR_STRT); | |
124 | ||
125 | while (readl(&flash_bank[bank]->sr) & STM32_FLASH_SR_BSY) | |
126 | ; | |
127 | } | |
128 | ||
129 | clrbits_le32(&flash_bank[bank]->cr, STM32_FLASH_CR_PER); | |
130 | ||
131 | stm32f1_flash_lock(bank, 1); | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
136 | int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt) | |
137 | { | |
138 | ulong i; | |
139 | u8 bank = 0xff; | |
140 | ||
141 | if (addr & 1) { | |
142 | printf("Flash address must be half word aligned\n"); | |
143 | return -1; | |
144 | } | |
145 | ||
146 | if (cnt & 1) { | |
147 | printf("Flash length must be half word aligned\n"); | |
148 | return -1; | |
149 | } | |
150 | ||
151 | for (i = 0; i < 2; i++) { | |
152 | if (info == &flash_info[i]) { | |
153 | bank = i; | |
154 | break; | |
155 | } | |
156 | } | |
157 | ||
158 | if (bank == 0xff) | |
159 | return -1; | |
160 | ||
161 | while (readl(&flash_bank[bank]->sr) & STM32_FLASH_SR_BSY) | |
162 | ; | |
163 | ||
164 | stm32f1_flash_lock(bank, 0); | |
165 | ||
166 | setbits_le32(&flash_bank[bank]->cr, STM32_FLASH_CR_PG); | |
167 | ||
168 | /* STM32F1 requires half word writes */ | |
169 | for (i = 0; i < cnt >> 1; i++) { | |
170 | *(u16 *)(addr + i * 2) = ((u16 *)src)[i]; | |
171 | while (readl(&flash_bank[bank]->sr) & STM32_FLASH_SR_BSY) | |
172 | ; | |
173 | } | |
174 | ||
175 | clrbits_le32(&flash_bank[bank]->cr, STM32_FLASH_CR_PG); | |
176 | ||
177 | stm32f1_flash_lock(bank, 1); | |
178 | ||
179 | return 0; | |
180 | } |