blob: 4e8a274d56df8f5ec9eff9ce9570f725bef95740 [file] [log] [blame]
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000015 */
16
17#include <stdint.h>
18#include <string.h>
19#include <stdlib.h>
Carl-Daniel Hailfinger11990da2013-07-13 23:21:05 +000020#include <errno.h>
Carl-Daniel Hailfingerdcef67e2010-06-21 23:20:15 +000021#include <sys/types.h>
Patrick Georgia9095a92010-09-30 17:03:32 +000022#if !defined (__DJGPP__) && !defined(__LIBPAYLOAD__)
Carl-Daniel Hailfinger11990da2013-07-13 23:21:05 +000023/* No file access needed/possible to get hardware access permissions. */
Carl-Daniel Hailfinger831e8f42010-05-30 22:24:40 +000024#include <unistd.h>
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000025#include <fcntl.h>
Patrick Georgia9095a92010-09-30 17:03:32 +000026#endif
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000027#include "flash.h"
Patrick Georgi32508eb2012-07-20 20:35:14 +000028#include "hwaccess.h"
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000029
Peter Lemenkov62829662012-12-29 19:26:55 +000030/* Prevent reordering and/or merging of reads/writes to hardware.
31 * Such reordering and/or merging would break device accesses which depend on the exact access order.
32 */
33static inline void sync_primitive(void)
Carl-Daniel Hailfingerd6bb8282012-07-21 17:27:08 +000034{
Stefan Taunerfb2d77c2015-02-10 08:03:10 +000035/* This is not needed for...
36 * - x86: uses uncached accesses which have a strongly ordered memory model.
37 * - MIPS: uses uncached accesses in mode 2 on /dev/mem which has also a strongly ordered memory model.
38 * - ARM: uses a strongly ordered memory model for device memories.
39 *
40 * See also https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/memory-barriers.txt
Peter Lemenkov62829662012-12-29 19:26:55 +000041 */
Thomas Heijligen3d5be0b2021-10-12 20:31:45 +020042// cf. http://lxr.free-electrons.com/source/arch/powerpc/include/asm/barrier.h
43#if defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || \
44 defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
45 defined(_ARCH_PPC64) || defined(__ppc)
Peter Lemenkov62829662012-12-29 19:26:55 +000046 asm("eieio" : : : "memory");
Thomas Heijligen3d5be0b2021-10-12 20:31:45 +020047#elif (__sparc__) || defined (__sparc)
Stefan Taunerfb2d77c2015-02-10 08:03:10 +000048#if defined(__sparc_v9__) || defined(__sparcv9)
49 /* Sparc V9 CPUs support three different memory orderings that range from x86-like TSO to PowerPC-like
50 * RMO. The modes can be switched at runtime thus to make sure we maintain the right order of access we
51 * use the strongest hardware memory barriers that exist on Sparc V9. */
52 asm volatile ("membar #Sync" ::: "memory");
53#elif defined(__sparc_v8__) || defined(__sparcv8)
54 /* On SPARC V8 there is no RMO just PSO and that does not apply to I/O accesses... but if V8 code is run
55 * on V9 CPUs it might apply... or not... we issue a write barrier anyway. That's the most suitable
56 * operation in the V8 instruction set anyway. If you know better then please tell us. */
57 asm volatile ("stbar");
58#else
59 #error Unknown and/or unsupported SPARC instruction set version detected.
60#endif
Peter Lemenkov62829662012-12-29 19:26:55 +000061#endif
62}
63
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000064void mmio_writeb(uint8_t val, void *addr)
65{
66 *(volatile uint8_t *) addr = val;
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +000067 sync_primitive();
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000068}
69
70void mmio_writew(uint16_t val, void *addr)
71{
72 *(volatile uint16_t *) addr = val;
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +000073 sync_primitive();
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000074}
75
76void mmio_writel(uint32_t val, void *addr)
77{
78 *(volatile uint32_t *) addr = val;
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +000079 sync_primitive();
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000080}
81
Nico Huberb4d8a2a2017-03-17 17:19:15 +010082uint8_t mmio_readb(const void *addr)
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000083{
Nico Huberb4d8a2a2017-03-17 17:19:15 +010084 return *(volatile const uint8_t *) addr;
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000085}
86
Nico Huberb4d8a2a2017-03-17 17:19:15 +010087uint16_t mmio_readw(const void *addr)
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000088{
Nico Huberb4d8a2a2017-03-17 17:19:15 +010089 return *(volatile const uint16_t *) addr;
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000090}
91
Nico Huberb4d8a2a2017-03-17 17:19:15 +010092uint32_t mmio_readl(const void *addr)
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000093{
Nico Huberb4d8a2a2017-03-17 17:19:15 +010094 return *(volatile const uint32_t *) addr;
Carl-Daniel Hailfingerfb0828f2010-02-12 19:35:25 +000095}
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +000096
Nico Huberb4d8a2a2017-03-17 17:19:15 +010097void mmio_readn(const void *addr, uint8_t *buf, size_t len)
Carl-Daniel Hailfingerccd71c22012-03-01 22:38:27 +000098{
99 memcpy(buf, addr, len);
100 return;
101}
102
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000103void mmio_le_writeb(uint8_t val, void *addr)
104{
105 mmio_writeb(cpu_to_le8(val), addr);
106}
107
108void mmio_le_writew(uint16_t val, void *addr)
109{
110 mmio_writew(cpu_to_le16(val), addr);
111}
112
113void mmio_le_writel(uint32_t val, void *addr)
114{
115 mmio_writel(cpu_to_le32(val), addr);
116}
117
Nico Huberb4d8a2a2017-03-17 17:19:15 +0100118uint8_t mmio_le_readb(const void *addr)
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000119{
120 return le_to_cpu8(mmio_readb(addr));
121}
122
Nico Huberb4d8a2a2017-03-17 17:19:15 +0100123uint16_t mmio_le_readw(const void *addr)
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000124{
125 return le_to_cpu16(mmio_readw(addr));
126}
127
Nico Huberb4d8a2a2017-03-17 17:19:15 +0100128uint32_t mmio_le_readl(const void *addr)
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000129{
130 return le_to_cpu32(mmio_readl(addr));
131}
Carl-Daniel Hailfinger54ce73a2011-05-03 21:49:41 +0000132
133enum mmio_write_type {
134 mmio_write_type_b,
135 mmio_write_type_w,
136 mmio_write_type_l,
137};
138
139struct undo_mmio_write_data {
140 void *addr;
141 int reg;
142 enum mmio_write_type type;
143 union {
144 uint8_t bdata;
145 uint16_t wdata;
146 uint32_t ldata;
147 };
148};
149
Jacob Garberbeeb8bc2019-06-21 15:24:17 -0600150static int undo_mmio_write(void *p)
Carl-Daniel Hailfinger54ce73a2011-05-03 21:49:41 +0000151{
152 struct undo_mmio_write_data *data = p;
153 msg_pdbg("Restoring MMIO space at %p\n", data->addr);
154 switch (data->type) {
155 case mmio_write_type_b:
156 mmio_writeb(data->bdata, data->addr);
157 break;
158 case mmio_write_type_w:
159 mmio_writew(data->wdata, data->addr);
160 break;
161 case mmio_write_type_l:
162 mmio_writel(data->ldata, data->addr);
163 break;
164 }
165 /* p was allocated in register_undo_mmio_write. */
166 free(p);
David Hendricks8bb20212011-06-14 01:35:36 +0000167 return 0;
Carl-Daniel Hailfinger54ce73a2011-05-03 21:49:41 +0000168}
169
170#define register_undo_mmio_write(a, c) \
171{ \
172 struct undo_mmio_write_data *undo_mmio_write_data; \
Angel Pons690a9442021-06-07 12:33:53 +0200173 undo_mmio_write_data = malloc(sizeof(*undo_mmio_write_data)); \
Stefan Tauner269de352011-07-12 22:35:21 +0000174 if (!undo_mmio_write_data) { \
175 msg_gerr("Out of memory!\n"); \
176 exit(1); \
177 } \
Carl-Daniel Hailfinger54ce73a2011-05-03 21:49:41 +0000178 undo_mmio_write_data->addr = a; \
179 undo_mmio_write_data->type = mmio_write_type_##c; \
180 undo_mmio_write_data->c##data = mmio_read##c(a); \
181 register_shutdown(undo_mmio_write, undo_mmio_write_data); \
182}
183
184#define register_undo_mmio_writeb(a) register_undo_mmio_write(a, b)
185#define register_undo_mmio_writew(a) register_undo_mmio_write(a, w)
186#define register_undo_mmio_writel(a) register_undo_mmio_write(a, l)
187
188void rmmio_writeb(uint8_t val, void *addr)
189{
190 register_undo_mmio_writeb(addr);
191 mmio_writeb(val, addr);
192}
193
194void rmmio_writew(uint16_t val, void *addr)
195{
196 register_undo_mmio_writew(addr);
197 mmio_writew(val, addr);
198}
199
200void rmmio_writel(uint32_t val, void *addr)
201{
202 register_undo_mmio_writel(addr);
203 mmio_writel(val, addr);
204}
205
206void rmmio_le_writeb(uint8_t val, void *addr)
207{
208 register_undo_mmio_writeb(addr);
209 mmio_le_writeb(val, addr);
210}
211
212void rmmio_le_writew(uint16_t val, void *addr)
213{
214 register_undo_mmio_writew(addr);
215 mmio_le_writew(val, addr);
216}
217
218void rmmio_le_writel(uint32_t val, void *addr)
219{
220 register_undo_mmio_writel(addr);
221 mmio_le_writel(val, addr);
222}
223
224void rmmio_valb(void *addr)
225{
226 register_undo_mmio_writeb(addr);
227}
228
229void rmmio_valw(void *addr)
230{
231 register_undo_mmio_writew(addr);
232}
233
234void rmmio_vall(void *addr)
235{
236 register_undo_mmio_writel(addr);
237}