File size: 4,616 Bytes
829b19c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | /*
* Driver — OMAP3530 GPMC NOR Flash driver
* Intel JS28F256M29EWH via GPMC CS0
*/
#include "nor_flash.h"
static hw_reg32_t nor_base(int cs) {
return (hw_reg32_t)(NOR_FLASH_BASE + cs * 0x10000000UL);
}
static void nor_write_cmd(int cs, uint32_t offset, uint16_t cmd) {
hw_reg32_t base = nor_base(cs);
volatile uint16_t *flash = (volatile uint16_t *)base;
flash[offset] = cmd;
__asm__ volatile("dmb" ::: "memory");
}
static uint16_t nor_read_reg(int cs, uint32_t offset) {
hw_reg32_t base = nor_base(cs);
volatile uint16_t *flash = (volatile uint16_t *)base;
return flash[offset];
}
int nor_flash_init(int cs) {
hw_reg32_t gpmc = (hw_reg32_t)GPMC_BASE;
/* Enable GPMC */
reg_write32(gpmc + GPMC_SYSCONFIG, 0x10); /* Smart idle */
delay_cycles(100);
/* Configure CS0 for 16-bit NOR flash, async */
reg_write32(gpmc + GPMC_CONFIG1(cs),
(0x00 << 0) | /* DEVICETYPE: NOR async */
(0x02 << 12) | /* MWIDTH: 16-bit */
(0x01 << 18) /* WAITPIN: WAIT0 */
);
/* CS signal timings — conservative for initial bring-up */
reg_write32(gpmc + GPMC_CONFIG2(cs),
(0x08 << 0) | /* CS_ON: 8 cycles */
(0x1F << 8) /* CS_WR_OFF: 31 cycles */
);
reg_write32(gpmc + GPMC_CONFIG3(cs),
(0x02 << 0) | /* ADV_ON: 2 cycles */
(0x06 << 8) /* ADV_WR_OFF: 6 cycles */
);
reg_write32(gpmc + GPMC_CONFIG4(cs),
(0x03 << 0) | /* OE_ON: 3 cycles */
(0x0C << 8) | /* OE_OFF: 12 cycles */
(0x03 << 16) | /* WE_ON: 3 cycles */
(0x0C << 24) /* WE_OFF: 12 cycles */
);
reg_write32(gpmc + GPMC_CONFIG5(cs),
(0x02 << 0) | /* RD_CYCLE: 2 extra */
(0x02 << 8) | /* WR_CYCLE: 2 extra */
(0x02 << 16) | /* RD_ACCESS: 2 cycles */
(0x02 << 24) /* WR_ACCESS: 2 cycles */
);
reg_write32(gpmc + GPMC_CONFIG6(cs),
(0x00 << 0) | /* WR_DATA_MUX: 0 */
(0x02 << 8) | /* WR_ACCESS: 2 cycles */
(0x00 << 16) /* CYCLE2CYCLE: no delay */
);
/* Set base address and enable CS */
reg32_t config7 = (0x08 << 0) | /* Base address bits [31:24] = 0x08 → 0x08000000 */
(0x0F << 8) | /* Mask: 256MB region */
GPMC_CONFIG7_CSVALID;
reg_write32(gpmc + GPMC_CONFIG7(cs), config7);
/* Reset flash to read mode */
nor_flash_reset(cs);
return 0;
}
void nor_flash_read_id(int cs, uint16_t *manufacturer, uint16_t *device) {
nor_write_cmd(cs, 0, NOR_CMD_READ_ID);
delay_cycles(100);
*manufacturer = nor_read_reg(cs, 0);
*device = nor_read_reg(cs, 1);
nor_flash_reset(cs);
}
void nor_flash_reset(int cs) {
nor_write_cmd(cs, 0, NOR_CMD_RESET);
delay_cycles(500);
}
int nor_flash_erase_sector(int cs, uint32_t offset) {
nor_write_cmd(cs, 0, NOR_CMD_ERASE);
nor_write_cmd(cs, offset >> 1, NOR_CMD_CONFIRM);
/* Poll for completion (status bit 7 toggles when done) */
volatile uint16_t *flash = (volatile uint16_t *)nor_base(cs);
uint32_t timeout = 5000000;
while (timeout--) {
uint16_t status = flash[offset >> 1];
if (status & 0x0080) /* DSQ7: done */
break;
}
nor_flash_reset(cs);
/* Verify erased (should read 0xFFFF) */
if (flash[offset >> 1] != 0xFFFF)
return -1;
return 0;
}
int nor_flash_program_word(int cs, uint32_t offset, uint16_t data) {
volatile uint16_t *flash = (volatile uint16_t *)nor_base(cs);
uint32_t word_offset = offset >> 1;
nor_write_cmd(cs, 0, NOR_CMD_PROG);
flash[word_offset] = data;
__asm__ volatile("dmb" ::: "memory");
/* Poll for completion */
uint32_t timeout = 1000000;
while (timeout--) {
uint16_t status = flash[word_offset];
if ((status & 0x0080) && (status == data))
break;
}
nor_flash_reset(cs);
if (flash[word_offset] != data)
return -1;
return 0;
}
int nor_flash_program_buf(int cs, uint32_t offset, const uint16_t *buf, uint32_t count) {
for (uint32_t i = 0; i < count; i++) {
if (nor_flash_program_word(cs, offset + i * 2, buf[i]) != 0)
return -1;
}
return 0;
}
int nor_flash_read_buf(int cs, uint32_t offset, uint16_t *buf, uint32_t count) {
volatile uint16_t *flash = (volatile uint16_t *)nor_base(cs);
uint32_t word_offset = offset >> 1;
for (uint32_t i = 0; i < count; i++) {
buf[i] = flash[word_offset + i];
}
return 0;
}
|