| /* |
| * Basic Flash Driver for Freescale MCF 5281/5282 internal FLASH |
| * |
| * (C) Copyright 2005 BuS Elektronik GmbH & Co.KG <esw@bus-elektonik.de> |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <common.h> |
| #include <asm/m5282.h> |
| #include "cfm_flash.h" |
| |
| #if defined(CONFIG_M5281) || defined(CONFIG_M5282) |
| |
| #if (CONFIG_SYS_CLK>20000000) |
| #define CFM_CLK (((long) CONFIG_SYS_CLK / (400000 * 8) + 1) | 0x40) |
| #else |
| #define CFM_CLK ((long) CONFIG_SYS_CLK / 400000 + 1) |
| #endif |
| |
| #define cmf_backdoor_address(addr) (((addr) & 0x0007FFFF) | 0x04000000 | \ |
| (CONFIG_SYS_MBAR & 0xC0000000)) |
| |
| void cfm_flash_print_info (flash_info_t * info) |
| { |
| printf ("Freescale: "); |
| switch (info->flash_id & FLASH_TYPEMASK) { |
| case FREESCALE_ID_MCF5281 & FLASH_TYPEMASK: |
| printf ("MCF5281 internal FLASH\n"); |
| break; |
| case FREESCALE_ID_MCF5282 & FLASH_TYPEMASK: |
| printf ("MCF5282 internal FLASH\n"); |
| break; |
| default: |
| printf ("Unknown Chip Type\n"); |
| break; |
| } |
| } |
| |
| void cfm_flash_init (flash_info_t * info) |
| { |
| int sector; |
| ulong protection; |
| MCFCFM_MCR = 0; |
| MCFCFM_CLKD = CFM_CLK; |
| debug ("CFM Clock divider: %ld (%d Hz @ %ld Hz)\n",CFM_CLK,\ |
| CONFIG_SYS_CLK / (2* ((CFM_CLK & 0x3F)+1) * (1+((CFM_CLK & 0x40)>>6)*7)),\ |
| CONFIG_SYS_CLK); |
| MCFCFM_SACC = 0; |
| MCFCFM_DACC = 0; |
| |
| if (MCFCFM_SEC & MCFCFM_SEC_KEYEN) |
| puts("CFM backdoor access is enabled\n"); |
| if (MCFCFM_SEC & MCFCFM_SEC_SECSTAT) |
| puts("CFM securety is enabled\n"); |
| |
| #ifdef CONFIG_M5281 |
| info->flash_id = (FREESCALE_MANUFACT & FLASH_VENDMASK) | |
| (FREESCALE_ID_MCF5281 & FLASH_TYPEMASK); |
| info->size = 256*1024; |
| info->sector_count = 16; |
| #else |
| info->flash_id = (FREESCALE_MANUFACT & FLASH_VENDMASK) | |
| (FREESCALE_ID_MCF5282 & FLASH_TYPEMASK); |
| info->size = 512*1024; |
| info->sector_count = 32; |
| #endif |
| protection = MCFCFM_PROT; |
| for (sector = 0; sector < info->sector_count; sector++) |
| { |
| if (sector == 0) |
| { |
| info->start[sector] = CONFIG_SYS_INT_FLASH_BASE; |
| } |
| else |
| { |
| info->start[sector] = info->start[sector-1] + 0x04000; |
| } |
| info->protect[sector] = protection & 1; |
| protection >>= 1; |
| } |
| } |
| |
| int cfm_flash_readycheck(int checkblank) |
| { |
| int rc; |
| unsigned char state; |
| |
| rc = ERR_OK; |
| while (!(MCFCFM_USTAT & MCFCFM_USTAT_CCIF)); |
| state = MCFCFM_USTAT; |
| if (state & MCFCFM_USTAT_ACCERR) |
| { |
| debug ("%s(): CFM access error",__FUNCTION__); |
| rc = ERR_PROG_ERROR; |
| } |
| if (state & MCFCFM_USTAT_PVIOL) |
| { |
| debug ("%s(): CFM protection violation",__FUNCTION__); |
| rc = ERR_PROTECTED; |
| } |
| if (checkblank) |
| { |
| if (!(state & MCFCFM_USTAT_BLANK)) |
| { |
| debug ("%s(): CFM erras error",__FUNCTION__); |
| rc = ERR_NOT_ERASED; |
| } |
| } |
| MCFCFM_USTAT = state & 0x34; /* reset state */ |
| return rc; |
| } |
| |
| /* Erase 16KiB = 8 2KiB pages */ |
| |
| int cfm_flash_erase_sector (flash_info_t * info, int sector) |
| { |
| ulong address; |
| int page; |
| int rc; |
| rc= ERR_OK; |
| address = cmf_backdoor_address(info->start[sector]); |
| for (page=0; (page<8) && (rc==ERR_OK); page++) |
| { |
| *(volatile __u32*) address = 0; |
| MCFCFM_CMD = MCFCFM_CMD_PGERS; |
| MCFCFM_USTAT = MCFCFM_USTAT_CBEIF; |
| rc = cfm_flash_readycheck(0); |
| if (rc==ERR_OK) |
| { |
| *(volatile __u32*) address = 0; |
| MCFCFM_CMD = MCFCFM_CMD_PGERSVER; |
| MCFCFM_USTAT = MCFCFM_USTAT_CBEIF; |
| rc = cfm_flash_readycheck(1); |
| } |
| address += 0x800; |
| } |
| return rc; |
| } |
| |
| int cfm_flash_write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) |
| { |
| int rc; |
| ulong dest, data; |
| |
| rc = ERR_OK; |
| if (addr & 3) |
| { |
| debug ("Byte and Word alignment not supported\n"); |
| rc = ERR_ALIGN; |
| } |
| if (cnt & 3) |
| { |
| debug ("Byte and Word transfer not supported\n"); |
| rc = ERR_ALIGN; |
| } |
| dest = cmf_backdoor_address(addr); |
| while ((cnt>=4) && (rc == ERR_OK)) |
| { |
| data = *((volatile u32 *) src); |
| *(volatile u32*) dest = data; |
| MCFCFM_CMD = MCFCFM_CMD_PGM; |
| MCFCFM_USTAT = MCFCFM_USTAT_CBEIF; |
| rc = cfm_flash_readycheck(0); |
| if (*(volatile u32*) addr != data) rc = ERR_PROG_ERROR; |
| src +=4; |
| dest +=4; |
| addr +=4; |
| cnt -=4; |
| } |
| return rc; |
| } |
| |
| #ifdef CONFIG_SYS_FLASH_PROTECTION |
| |
| int cfm_flash_protect(flash_info_t * info,long sector,int prot) |
| { |
| int rc; |
| |
| rc= ERR_OK; |
| if (prot) |
| { |
| MCFCFM_PROT |= (1<<sector); |
| info->protect[sector]=1; |
| } |
| else |
| { |
| MCFCFM_PROT &= ~(1<<sector); |
| info->protect[sector]=0; |
| } |
| return rc; |
| } |
| |
| #endif |
| |
| #endif |