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