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