1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2021 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "mx25r_flash.h"
10
11 #define MX25R_BYTE_ADDR1(address) ((uint8_t)(((address) >> 16UL) & 0x0FUL))
12 #define MX25R_BYTE_ADDR2(address) ((uint8_t)(((address) >> 8UL) & 0x0FUL))
13 #define MX25R_BYTE_ADDR3(address) ((uint8_t)((address)&0x0FUL))
14
15 /* initialize 'mx25r_instance' */
mx25r_init(struct mx25r_instance * instance,transfer_cb_t callback,void * callback_prv)16 mx25r_err_t mx25r_init(struct mx25r_instance *instance, transfer_cb_t callback, void *callback_prv)
17 {
18 instance->callback = callback;
19 instance->prv = callback_prv;
20 return mx25r_err_ok;
21 }
22
23 /* read 'rdid' to 'result' */
mx25r_cmd_rdid(struct mx25r_instance * instance,struct mx25r_rdid_result * result)24 mx25r_err_t mx25r_cmd_rdid(struct mx25r_instance *instance, struct mx25r_rdid_result *result)
25 {
26 instance->cmd[0] = 0x9f;
27 instance->callback(instance->prv, instance->cmd, NULL, 1, false);
28 instance->callback(instance->prv, NULL, (uint8_t *)result, sizeof(*result), true);
29 return mx25r_err_ok;
30 }
31
32 /* read n bytes starting at 'address' */
mx25r_cmd_read(struct mx25r_instance * instance,uint32_t address,uint8_t * buffer,uint32_t size)33 mx25r_err_t mx25r_cmd_read(struct mx25r_instance *instance, uint32_t address, uint8_t *buffer, uint32_t size)
34 {
35 if ((address & 0xFF000000U) != 0x00U)
36 {
37 return mx25r_err_out_of_range;
38 }
39 instance->cmd[0] = 0x03;
40 instance->cmd[1] = MX25R_BYTE_ADDR1(address);
41 instance->cmd[2] = MX25R_BYTE_ADDR2(address);
42 instance->cmd[3] = MX25R_BYTE_ADDR3(address);
43 instance->callback(instance->prv, instance->cmd, NULL, 4, false);
44 instance->callback(instance->prv, NULL, (uint8_t *)buffer, size, true);
45 return mx25r_err_ok;
46 }
47
48 /* no operation */
mx25r_cmd_nop(struct mx25r_instance * instance)49 mx25r_err_t mx25r_cmd_nop(struct mx25r_instance *instance)
50 {
51 instance->callback(instance->prv, instance->cmd, NULL, 1, true);
52 return mx25r_err_ok;
53 }
54
55 /* read status register */
mx25r_cmd_rdsr(struct mx25r_instance * instance,struct mx25r_rdsr_result * result)56 mx25r_err_t mx25r_cmd_rdsr(struct mx25r_instance *instance, struct mx25r_rdsr_result *result)
57 {
58 instance->cmd[0] = 0x05;
59 instance->callback(instance->prv, instance->cmd, NULL, 1, false);
60 instance->callback(instance->prv, NULL, (uint8_t *)result, sizeof(*result), true);
61 return mx25r_err_ok;
62 }
63
64 /* disable write operations */
mx25r_cmd_wrdi(struct mx25r_instance * instance)65 mx25r_err_t mx25r_cmd_wrdi(struct mx25r_instance *instance)
66 {
67 instance->cmd[0] = 0x04;
68 instance->callback(instance->prv, instance->cmd, NULL, 1, true);
69 return mx25r_err_ok;
70 }
71
72 /* enable write operations */
mx25r_cmd_wren(struct mx25r_instance * instance)73 mx25r_err_t mx25r_cmd_wren(struct mx25r_instance *instance)
74 {
75 instance->cmd[0] = 0x06;
76 instance->callback(instance->prv, instance->cmd, NULL, 1, true);
77 return mx25r_err_ok;
78 }
79
80 /* write n bytes (256 max) starting at 'address' aligned to 256 */
mx25r_cmd_write(struct mx25r_instance * instance,uint32_t address_256_align,uint8_t * buffer,uint32_t size_256_max)81 mx25r_err_t mx25r_cmd_write(struct mx25r_instance *instance,
82 uint32_t address_256_align,
83 uint8_t *buffer,
84 uint32_t size_256_max)
85 {
86 struct mx25r_rdsr_result result;
87 if ((address_256_align & 0xFF000000U) != 0x00U)
88 {
89 return mx25r_err_out_of_range;
90 }
91 if ((address_256_align & 0xFFU) != 0x00U)
92 {
93 return mx25r_err_alignement;
94 }
95 if (size_256_max > 256U)
96 {
97 return mx25r_err_out_of_range;
98 }
99 /* enable write and wait until WEL is 1 */
100 (void)mx25r_cmd_wren(instance);
101 do
102 {
103 (void)mx25r_cmd_rdsr(instance, &result);
104 } while (((uint8_t)result.sr0 & 0x2U) == 0x00U);
105 /* write sequence */
106 instance->cmd[0] = 0x02;
107 instance->cmd[1] = MX25R_BYTE_ADDR1(address_256_align);
108 instance->cmd[2] = MX25R_BYTE_ADDR2(address_256_align);
109 instance->cmd[3] = 0;
110 instance->callback(instance->prv, instance->cmd, NULL, 4, false);
111 instance->callback(instance->prv, (uint8_t *)buffer, NULL, size_256_max, true);
112 /* wait until WRI is 0 and WEL is 0 */
113 do
114 {
115 (void)mx25r_cmd_rdsr(instance, &result);
116 } while (((uint8_t)result.sr0 & 0x3U) != 0x00U);
117 return mx25r_err_ok;
118 }
119
120 /* erase sector at 'address' aligned to sector size = 4kB */
mx25r_cmd_sector_erase(struct mx25r_instance * instance,uint32_t address)121 mx25r_err_t mx25r_cmd_sector_erase(struct mx25r_instance *instance, uint32_t address)
122 {
123 struct mx25r_rdsr_result result;
124 /* enable write and wait until WEL is 1 */
125 (void)mx25r_cmd_wren(instance);
126 do
127 {
128 (void)mx25r_cmd_rdsr(instance, &result);
129 } while (((uint8_t)result.sr0 & 0x2U) == 0x00U);
130 /* write sequence */
131 instance->cmd[0] = 0x20;
132 instance->cmd[1] = MX25R_BYTE_ADDR1(address);
133 instance->cmd[2] = MX25R_BYTE_ADDR2(address);
134 instance->cmd[3] = MX25R_BYTE_ADDR3(address);
135 instance->callback(instance->prv, instance->cmd, NULL, 4, true);
136 /* wait until WRI is 0 and WEL is 0 */
137 do
138 {
139 (void)mx25r_cmd_rdsr(instance, &result);
140 } while (((uint8_t)result.sr0 & 0x3U) != 0x00U);
141 return mx25r_err_ok;
142 }
143