Add ICH9 detection to flashrom. Straight from the datasheet, untested.
[coreboot.git] / util / flashrom / sharplhf00l04.c
index e7e5eedfeaacbf00df4e3a3a49b99637ba85ed07..da7dc3f214462de125fa85531d58406dce6106af 100644 (file)
 /*
- * sst28sf040.c: driver for SST28SF040C flash models.
+ * This file is part of the flashrom project.
  *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
  *
- * Copyright 2000 Silicon Integrated System Corporation
- * Copyright 2005 coresystems GmbH <stepan@openbios.org>
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * Reference:
- *     8 MEgabit (1024K x 8) SHARP LHF00L04, data sheet
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
 #include <stdio.h>
-#include <stdint.h>
+#include <stdlib.h>
 #include "flash.h"
-#include "debug.h"
 
-
-#define AUTO_PG_ERASE1         0x20
-#define AUTO_PG_ERASE2         0xD0
-#define AUTO_PGRM              0x10
-#define CHIP_ERASE             0x30
-#define RESET                  0xFF
-#define READ_ID                        0x90
-
-static __inline__ void protect_lhf00l04(volatile uint8_t *bios)
+// I need that Berkeley bit-map printer
+void print_lhf00l04_status(uint8_t status)
 {
-       /* ask compiler not to optimize this */
-//     volatile uint8_t tmp;
-
+       printf("%s", status & 0x80 ? "Ready:" : "Busy:");
+       printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
+       printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
+       printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
+       printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
+       printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
+       printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
 }
 
-static __inline__ void unprotect_lhf00l04(volatile uint8_t *bios)
+int probe_lhf00l04(struct flashchip *flash)
 {
-       /* ask compiler not to optimize this */
-//     volatile uint8_t tmp;
-}
+       volatile uint8_t *bios = flash->virtual_memory;
+       uint8_t id1, id2;
 
-static __inline__ int erase_sector_lhf00l04(volatile uint8_t *bios,
-                                          unsigned long address)
-{
+#if 0
+       /* Enter ID mode */
+       *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
+       *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
+       *(volatile uint8_t *)(bios + 0x5555) = 0x90;
+#endif
 
-       return (0);
-}
+       *bios = 0xff;
+       myusec_delay(10);
+       *bios = 0x90;
+       myusec_delay(10);
 
-static __inline__ int write_sector_lhf00l04(volatile uint8_t *bios,
-                                          uint8_t *src,
-                                          volatile uint8_t *dst,
-                                          unsigned int page_size)
-{
-       int i;
+       id1 = *(volatile uint8_t *)bios;
+       id2 = *(volatile uint8_t *)(bios + 0x01);
 
-       for (i = 0; i < page_size; i++) {
-               /* transfer data from source to destination */
-               if (*src == 0xFF) {
-                       dst++, src++;
-                       /* If the data is 0xFF, don't program it */
-                       continue;
-               }
-               /*issue AUTO PROGRAM command */
-               *dst = AUTO_PGRM;
-               *dst++ = *src++;
+       /* Leave ID mode */
+       *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
+       *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
+       *(volatile uint8_t *)(bios + 0x5555) = 0xF0;
 
-               /* wait for Toggle bit ready */
-//             toggle_ready_jedec(bios);
-       }
+       myusec_delay(10);
 
-       return (0);
+       printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
+
+       if (id1 != flash->manufacture_id || id2 != flash->model_id)
+               return 0;
+
+       map_flash_registers(flash);
+
+       return 1;
 }
 
-int probe_lhf00l04(struct flashchip *flash)
+uint8_t wait_lhf00l04(volatile uint8_t *bios)
 {
-       volatile uint8_t *bios = flash->virt_addr;
-       uint8_t id1, id2, tmp;
+       uint8_t status;
+       uint8_t id1, id2;
 
-       /* save the value at the beginning of the Flash */
-       tmp = *bios;
+       *bios = 0x70;
+       if ((*bios & 0x80) == 0) {      // it's busy
+               while ((*bios & 0x80) == 0) ;
+       }
 
-       *bios = RESET;
-       myusec_delay(10);
+       status = *bios;
 
-       *bios = READ_ID;
-       myusec_delay(10);
-       id1 = *(volatile uint8_t *) bios;
-       myusec_delay(10);
-       id2 = *(volatile uint8_t *) (bios + 0x01);
+       // put another command to get out of status register mode
 
-       *bios = RESET;
+       *bios = 0x90;
        myusec_delay(10);
 
-       printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
-       if (id1 == flash->manufacture_id && id2 == flash->model_id)
-               return 1;
+       id1 = *(volatile uint8_t *)bios;
+       id2 = *(volatile uint8_t *)(bios + 0x01);
+
+       // this is needed to jam it out of "read id" mode
+       *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
+       *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
+       *(volatile uint8_t *)(bios + 0x5555) = 0xF0;
+
+       return status;
+}
+
+int erase_lhf00l04_block(struct flashchip *flash, int offset)
+{
+       volatile uint8_t *bios = flash->virtual_memory + offset;
+       volatile uint8_t *wrprotect = flash->virtual_registers + offset + 2;
+       uint8_t status;
+
+       // clear status register
+       *bios = 0x50;
+       printf("Erase at %p\n", bios);
+       status = wait_lhf00l04(flash->virtual_memory);
+       print_lhf00l04_status(status);
+       // clear write protect
+       printf("write protect is at %p\n", (wrprotect));
+       printf("write protect is 0x%x\n", *(wrprotect));
+       *(wrprotect) = 0;
+       printf("write protect is 0x%x\n", *(wrprotect));
+
+       // now start it
+       *(volatile uint8_t *)(bios) = 0x20;
+       *(volatile uint8_t *)(bios) = 0xd0;
+       myusec_delay(10);
+       // now let's see what the register is
+       status = wait_lhf00l04(flash->virtual_memory);
+       print_lhf00l04_status(status);
+       printf("DONE BLOCK 0x%x\n", offset);
 
-       /* if there is no lhf00l04, restore the original value */
-       *bios = tmp;
        return 0;
 }
 
 int erase_lhf00l04(struct flashchip *flash)
 {
-       volatile uint8_t *bios = flash->virt_addr;
-
-       unprotect_lhf00l04(bios);
-       *bios = CHIP_ERASE;
-       *bios = CHIP_ERASE;
-       protect_lhf00l04(bios);
+       int i;
+       unsigned int total_size = flash->total_size * 1024;
 
-       myusec_delay(10);
-//     toggle_ready_jedec(bios);
+       printf("total_size is %d; flash->page_size is %d\n",
+              total_size, flash->page_size);
+       for (i = 0; i < total_size; i += flash->page_size)
+               erase_lhf00l04_block(flash, i);
+       printf("DONE ERASE\n");
 
-       return (0);
+       return 0;
 }
 
-int write_lhf00l04(struct flashchip *flash, uint8_t *buf)
+void write_page_lhf00l04(volatile uint8_t *bios, uint8_t *src,
+                        volatile uint8_t *dst, int page_size)
 {
        int i;
-       int total_size = flash->total_size * 1024, page_size =
-           flash->page_size;
-       volatile uint8_t *bios = flash->virt_addr;
 
-       unprotect_lhf00l04(bios);
+       for (i = 0; i < page_size; i++) {
+               /* transfer data from source to destination */
+               *dst = 0x40;
+               *dst++ = *src++;
+               wait_lhf00l04(bios);
+       }
+}
 
-       printf("Programming Page: ");
+int write_lhf00l04(struct flashchip *flash, uint8_t *buf)
+{
+       int i;
+       int total_size = flash->total_size * 1024;
+       int page_size = flash->page_size;
+       volatile uint8_t *bios = flash->virtual_memory;
+
+       erase_lhf00l04(flash);
+       if (*bios != 0xff) {
+               printf("ERASE FAILED!\n");
+               return -1;
+       }
+       printf("Programming page: ");
        for (i = 0; i < total_size / page_size; i++) {
-               /* erase the page before programming */
-               erase_sector_lhf00l04(bios, i * page_size);
-
-               /* write to the sector */
                printf("%04d at address: 0x%08x", i, i * page_size);
-               write_sector_lhf00l04(bios, buf + i * page_size,
-                                    bios + i * page_size, page_size);
+               write_page_lhf00l04(bios, buf + i * page_size,
+                                   bios + i * page_size, page_size);
                printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
        }
        printf("\n");
+       protect_jedec(bios);
 
-       protect_lhf00l04(bios);
-
-       return (0);
+       return 0;
 }