blob: fe03b17581103efcf2905af50674e6064207785a [file] [log] [blame]
Heiko Schocherac1956e2006-04-20 08:42:42 +02001/*
2 * Basic Flash Driver for Freescale MCF 5281/5282 internal FLASH
3 *
4 * (C) Copyright 2005 BuS Elektronik GmbH & Co.KG <esw@bus-elektonik.de>
5 *
6 * See file CREDITS for list of people who contributed to this
7 * project.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 */
24
Wolfgang Denkf7290752006-06-10 22:00:40 +020025#include <common.h>
Heiko Schocherac1956e2006-04-20 08:42:42 +020026#include <asm/m5282.h>
27#include "cfm_flash.h"
28
29#if defined(CONFIG_M5281) || defined(CONFIG_M5282)
30
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020031#if (CONFIG_SYS_CLK>20000000)
32 #define CFM_CLK (((long) CONFIG_SYS_CLK / (400000 * 8) + 1) | 0x40)
Heiko Schocherac1956e2006-04-20 08:42:42 +020033#else
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020034 #define CFM_CLK ((long) CONFIG_SYS_CLK / 400000 + 1)
Heiko Schocherac1956e2006-04-20 08:42:42 +020035#endif
36
37#define cmf_backdoor_address(addr) (((addr) & 0x0007FFFF) | 0x04000000 | \
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020038 (CONFIG_SYS_MBAR & 0xC0000000))
Heiko Schocherac1956e2006-04-20 08:42:42 +020039
40void cfm_flash_print_info (flash_info_t * info)
41{
42 printf ("Freescale: ");
43 switch (info->flash_id & FLASH_TYPEMASK) {
44 case FREESCALE_ID_MCF5281 & FLASH_TYPEMASK:
45 printf ("MCF5281 internal FLASH\n");
46 break;
47 case FREESCALE_ID_MCF5282 & FLASH_TYPEMASK:
48 printf ("MCF5282 internal FLASH\n");
49 break;
50 default:
51 printf ("Unknown Chip Type\n");
52 break;
53 }
54}
55
56void cfm_flash_init (flash_info_t * info)
57{
58 int sector;
59 ulong protection;
60 MCFCFM_MCR = 0;
61 MCFCFM_CLKD = CFM_CLK;
62 debug ("CFM Clock divider: %ld (%d Hz @ %ld Hz)\n",CFM_CLK,\
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020063 CONFIG_SYS_CLK / (2* ((CFM_CLK & 0x3F)+1) * (1+((CFM_CLK & 0x40)>>6)*7)),\
64 CONFIG_SYS_CLK);
Heiko Schocherac1956e2006-04-20 08:42:42 +020065 MCFCFM_SACC = 0;
66 MCFCFM_DACC = 0;
67
68 if (MCFCFM_SEC & MCFCFM_SEC_KEYEN)
69 puts("CFM backdoor access is enabled\n");
70 if (MCFCFM_SEC & MCFCFM_SEC_SECSTAT)
71 puts("CFM securety is enabled\n");
72
73 #ifdef CONFIG_M5281
74 info->flash_id = (FREESCALE_MANUFACT & FLASH_VENDMASK) |
75 (FREESCALE_ID_MCF5281 & FLASH_TYPEMASK);
76 info->size = 256*1024;
77 info->sector_count = 16;
78 #else
79 info->flash_id = (FREESCALE_MANUFACT & FLASH_VENDMASK) |
80 (FREESCALE_ID_MCF5282 & FLASH_TYPEMASK);
81 info->size = 512*1024;
82 info->sector_count = 32;
83 #endif
84 protection = MCFCFM_PROT;
85 for (sector = 0; sector < info->sector_count; sector++)
86 {
87 if (sector == 0)
88 {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020089 info->start[sector] = CONFIG_SYS_INT_FLASH_BASE;
Heiko Schocherac1956e2006-04-20 08:42:42 +020090 }
91 else
92 {
93 info->start[sector] = info->start[sector-1] + 0x04000;
94 }
95 info->protect[sector] = protection & 1;
96 protection >>= 1;
97 }
98}
99
100int cfm_flash_readycheck(int checkblank)
101{
102 int rc;
103 unsigned char state;
104
105 rc = ERR_OK;
106 while (!(MCFCFM_USTAT & MCFCFM_USTAT_CCIF));
107 state = MCFCFM_USTAT;
108 if (state & MCFCFM_USTAT_ACCERR)
109 {
110 debug ("%s(): CFM access error",__FUNCTION__);
111 rc = ERR_PROG_ERROR;
112 }
113 if (state & MCFCFM_USTAT_PVIOL)
114 {
115 debug ("%s(): CFM protection violation",__FUNCTION__);
116 rc = ERR_PROTECTED;
117 }
118 if (checkblank)
119 {
120 if (!(state & MCFCFM_USTAT_BLANK))
121 {
122 debug ("%s(): CFM erras error",__FUNCTION__);
123 rc = ERR_NOT_ERASED;
124 }
125 }
126 MCFCFM_USTAT = state & 0x34; /* reset state */
127 return rc;
128}
129
130/* Erase 16KiB = 8 2KiB pages */
131
132int cfm_flash_erase_sector (flash_info_t * info, int sector)
133{
134 ulong address;
135 int page;
136 int rc;
137 rc= ERR_OK;
138 address = cmf_backdoor_address(info->start[sector]);
139 for (page=0; (page<8) && (rc==ERR_OK); page++)
140 {
141 *(volatile __u32*) address = 0;
142 MCFCFM_CMD = MCFCFM_CMD_PGERS;
143 MCFCFM_USTAT = MCFCFM_USTAT_CBEIF;
144 rc = cfm_flash_readycheck(0);
145 if (rc==ERR_OK)
146 {
147 *(volatile __u32*) address = 0;
148 MCFCFM_CMD = MCFCFM_CMD_PGERSVER;
149 MCFCFM_USTAT = MCFCFM_USTAT_CBEIF;
150 rc = cfm_flash_readycheck(1);
151 }
152 address += 0x800;
153 }
154 return rc;
155}
156
157int cfm_flash_write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
158{
159 int rc;
160 ulong dest, data;
161
162 rc = ERR_OK;
163 if (addr & 3)
164 {
165 debug ("Byte and Word alignment not supported\n");
166 rc = ERR_ALIGN;
167 }
168 if (cnt & 3)
169 {
170 debug ("Byte and Word transfer not supported\n");
171 rc = ERR_ALIGN;
172 }
173 dest = cmf_backdoor_address(addr);
174 while ((cnt>=4) && (rc == ERR_OK))
175 {
Wolfgang Denkdc770c72008-07-14 15:19:07 +0200176 data = *((volatile u32 *) src);
Heiko Schocherac1956e2006-04-20 08:42:42 +0200177 *(volatile u32*) dest = data;
178 MCFCFM_CMD = MCFCFM_CMD_PGM;
179 MCFCFM_USTAT = MCFCFM_USTAT_CBEIF;
180 rc = cfm_flash_readycheck(0);
181 if (*(volatile u32*) addr != data) rc = ERR_PROG_ERROR;
182 src +=4;
183 dest +=4;
184 addr +=4;
185 cnt -=4;
186 }
187 return rc;
188}
189
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200190#ifdef CONFIG_SYS_FLASH_PROTECTION
Heiko Schocherac1956e2006-04-20 08:42:42 +0200191
192int cfm_flash_protect(flash_info_t * info,long sector,int prot)
193{
194 int rc;
195
196 rc= ERR_OK;
197 if (prot)
198 {
199 MCFCFM_PROT |= (1<<sector);
200 info->protect[sector]=1;
201 }
202 else
203 {
204 MCFCFM_PROT &= ~(1<<sector);
205 info->protect[sector]=0;
206 }
207 return rc;
208}
209
210#endif
211
212#endif