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