1 // Copyright (C) 2015 Playground Global LLC. All rights reserved.
2
3 #include <lk/debug.h>
4 #include <assert.h>
5 #include <lk/trace.h>
6 #include <lk/compiler.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <lk/err.h>
10 #include <string.h>
11 #include <lk/reg.h>
12 #include <lib/bio.h>
13 #include <lk/console_cmd.h>
14 #include <kernel/thread.h>
15 #include <stm32f4xx_flash.h>
16
17 #define LOCAL_TRACE 0
18
19 #define SECTORS 12
20
21 static u32 sectors[SECTORS + 1] = {
22 0x08000000,
23 0x08004000,
24 0x08008000,
25 0x0800C000,
26 0x08010000,
27 0x08020000,
28 0x08040000,
29 0x08060000,
30 0x08080000,
31 0x080A0000,
32 0x080C0000,
33 0x080E0000,
34 0x08100000,
35 };
36
37
38 typedef struct intflash_s {
39 bool initialized;
40 bdev_t bdev;
41 uint32_t start;
42 } intflash_t;
43
44 static intflash_t sg_flash = { 0 };
45 static ssize_t stmflash_bdev_read(struct bdev *, void *buf, off_t offset, size_t len);
46 static ssize_t stmflash_bdev_read_block(struct bdev *, void *buf, bnum_t block, uint count);
47 static ssize_t stmflash_bdev_write(struct bdev *, const void *buf, off_t offset, size_t len);
48 static ssize_t stmflash_bdev_write_block(struct bdev *, const void *buf, bnum_t block, uint count);
49 static ssize_t stmflash_bdev_erase(struct bdev *, off_t offset, size_t len);
50 static int stmflash_ioctl(struct bdev *, int request, void *argp);
51
stmflash_init(uint32_t start,uint32_t length)52 status_t stmflash_init(uint32_t start, uint32_t length) {
53 memset(&sg_flash, 0, sizeof(intflash_t));
54 sg_flash.start = start;
55 /* construct the block device */
56 bio_initialize_bdev(&sg_flash.bdev,
57 "flash0",
58 1,
59 length,
60 0,
61 NULL,
62 BIO_FLAGS_NONE);
63
64 /* override our block device hooks */
65 sg_flash.bdev.read = &stmflash_bdev_read;
66 sg_flash.bdev.read_block = &stmflash_bdev_read_block;
67 sg_flash.bdev.write = &stmflash_bdev_write;
68 sg_flash.bdev.write_block = &stmflash_bdev_write_block;
69 sg_flash.bdev.erase = &stmflash_bdev_erase;
70 sg_flash.bdev.ioctl = &stmflash_ioctl;
71 bio_register_device(&sg_flash.bdev);
72 sg_flash.initialized = true;
73 return NO_ERROR;
74 }
75
76 // bio layer hooks
stmflash_bdev_read(struct bdev * bdev,void * buf,off_t offset,size_t len)77 static ssize_t stmflash_bdev_read(struct bdev *bdev, void *buf, off_t offset, size_t len) {
78 uint32_t startAddress = sg_flash.start;
79 LTRACEF("dev %p, buf %p, offset 0x%llx, len 0x%zx\n", bdev, buf, offset, len);
80 len = bio_trim_range(bdev, offset, len);
81 if (0 == len) {
82 return 0;
83 }
84 startAddress += offset;
85 memcpy(buf, (uint32_t *)(startAddress), len);
86 return len;
87 }
88
stmflash_bdev_read_block(struct bdev * bdev,void * buf,bnum_t block,uint count)89 static ssize_t stmflash_bdev_read_block(struct bdev *bdev, void *buf, bnum_t block, uint count) {
90 LTRACEF("dev %p, buf %p, block 0x%x, count %u\n",bdev, buf, block, count);
91 return 0;
92 }
93
stmflash_bdev_write(struct bdev * bdev,const void * buf,off_t offset,size_t len)94 static ssize_t stmflash_bdev_write(struct bdev *bdev, const void *buf, off_t offset, size_t len) {
95 uint32_t i, start_address;
96 LTRACEF("dev %p, buf %p, offset 0x%llx, len 0x%zx\n",bdev, buf, offset, len);
97 len = bio_trim_range(bdev, offset, len);
98 if (0 == len) {
99 return 0;
100 }
101 start_address = sg_flash.start+offset;
102 FLASH_Unlock();
103 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
104 FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
105 const uint32_t *_buf = buf;
106 for (i = 0; i < len / 4; i++) {
107 if (FLASH_COMPLETE == FLASH_ProgramWord(start_address,_buf[i])) {
108 start_address += 4;
109 } else {
110 len = 0;
111 break;
112 }
113 }
114 FLASH_Lock();
115 return len;
116 }
117
stmflash_bdev_write_block(struct bdev * bdev,const void * _buf,bnum_t block,uint count)118 static ssize_t stmflash_bdev_write_block(struct bdev *bdev, const void *_buf, bnum_t block, uint count) {
119 LTRACEF("dev %p, buf %p, block 0x%x, count %u\n",bdev, _buf, block, count);
120 count = bio_trim_block_range(bdev, block, count);
121 return 0;
122 }
123
stmflash_bdev_erase(struct bdev * bdev,off_t offset,size_t len)124 static ssize_t stmflash_bdev_erase(struct bdev *bdev, off_t offset, size_t len) {
125 uint8_t n;
126 LTRACEF("dev %p, offset 0x%llx, len 0x%zx\n",bdev, offset, len);
127 len = bio_trim_range(bdev, offset, len);
128 if (0 == len) {
129 return 0;
130 }
131 for (n = 0; n < SECTORS; n++) {
132 if (sectors[n] == sg_flash.start+offset) {
133 break;
134 }
135 }
136 if (SECTORS == n) {
137 return 0;
138 }
139 FLASH_Unlock();
140 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
141 FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
142 for (;;) {
143 if (FLASH_EraseSector(n<<3, VoltageRange_3) != FLASH_COMPLETE) {
144 FLASH_Lock();
145 return 0;
146 }
147 n++;
148 if (SECTORS == n) {
149 break;
150 }
151 if ((sectors[n] - (sg_flash.start+offset)) >= len) {
152 break;
153 }
154 }
155 FLASH_Lock();
156 return len;
157 }
158
stmflash_ioctl(struct bdev * bdev,int request,void * argp)159 static int stmflash_ioctl(struct bdev *bdev, int request, void *argp) {
160 LTRACEF("dev %p, request %d, argp %p\n",bdev, request, argp);
161 return ERR_NOT_SUPPORTED;
162 }
163