2 * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 FILE_LICENCE ( GPL2_OR_LATER
);
23 #include <gpxe/efi/efi.h>
24 #include <gpxe/efi/Protocol/CpuIo.h>
25 #include <gpxe/efi/efi_io.h>
29 * gPXE I/O API for EFI
33 /** CPU I/O protocol */
34 static EFI_CPU_IO_PROTOCOL
*cpu_io
;
35 EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL
, &cpu_io
);
37 /** Maximum address that can be used for port I/O */
38 #define MAX_PORT_ADDRESS 0xffff
41 * Determine whether or not address is a port I/O address
43 * @v io_addr I/O address
44 * @v is_port I/O address is a port I/O address
46 #define IS_PORT_ADDRESS(io_addr) \
47 ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
50 * Determine EFI CPU I/O width code
52 * @v size Size of value
53 * @ret width EFI width code
55 * Someone at Intel clearly gets paid by the number of lines of code
56 * they write. No-one should ever be able to make I/O this
57 * convoluted. The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
60 static EFI_CPU_IO_PROTOCOL_WIDTH
efi_width ( size_t size
) {
62 case 1 : return EfiCpuIoWidthFifoUint8
;
63 case 2 : return EfiCpuIoWidthFifoUint16
;
64 case 4 : return EfiCpuIoWidthFifoUint32
;
65 case 8 : return EfiCpuIoWidthFifoUint64
;
68 /* I wonder what this will actually do... */
69 return EfiCpuIoWidthMaximum
;
76 * @v io_addr I/O address
77 * @v size Size of value
78 * @ret data Value read
80 unsigned long long efi_ioread ( volatile void *io_addr
, size_t size
) {
81 EFI_CPU_IO_PROTOCOL_IO_MEM read
;
82 unsigned long long data
= 0;
85 read
= ( IS_PORT_ADDRESS ( io_addr
) ?
86 cpu_io
->Io
.Read
: cpu_io
->Mem
.Read
);
88 if ( ( efirc
= read ( cpu_io
, efi_width ( size
),
89 ( intptr_t ) io_addr
, 1,
90 ( void * ) &data
) ) != 0 ) {
91 DBG ( "EFI I/O read at %p failed: %s\n",
92 io_addr
, efi_strerror ( efirc
) );
102 * @v data Value to write
103 * @v io_addr I/O address
104 * @v size Size of value
106 void efi_iowrite ( unsigned long long data
, volatile void *io_addr
,
108 EFI_CPU_IO_PROTOCOL_IO_MEM write
;
111 write
= ( IS_PORT_ADDRESS ( io_addr
) ?
112 cpu_io
->Io
.Write
: cpu_io
->Mem
.Write
);
114 if ( ( efirc
= write ( cpu_io
, efi_width ( size
),
115 ( intptr_t ) io_addr
, 1,
116 ( void * ) &data
) ) != 0 ) {
117 DBG ( "EFI I/O write at %p failed: %s\n",
118 io_addr
, efi_strerror ( efirc
) );
123 * String read from device
125 * @v io_addr I/O address
126 * @v data Data buffer
127 * @v size Size of values
128 * @v count Number of values to read
130 void efi_ioreads ( volatile void *io_addr
, void *data
,
131 size_t size
, unsigned int count
) {
132 EFI_CPU_IO_PROTOCOL_IO_MEM read
;
135 read
= ( IS_PORT_ADDRESS ( io_addr
) ?
136 cpu_io
->Io
.Read
: cpu_io
->Mem
.Read
);
138 if ( ( efirc
= read ( cpu_io
, efi_width ( size
),
139 ( intptr_t ) io_addr
, count
,
140 ( void * ) data
) ) != 0 ) {
141 DBG ( "EFI I/O string read at %p failed: %s\n",
142 io_addr
, efi_strerror ( efirc
) );
147 * String write to device
149 * @v io_addr I/O address
150 * @v data Data buffer
151 * @v size Size of values
152 * @v count Number of values to write
154 void efi_iowrites ( volatile void *io_addr
, const void *data
,
155 size_t size
, unsigned int count
) {
156 EFI_CPU_IO_PROTOCOL_IO_MEM write
;
159 write
= ( IS_PORT_ADDRESS ( io_addr
) ?
160 cpu_io
->Io
.Write
: cpu_io
->Mem
.Write
);
162 if ( ( efirc
= write ( cpu_io
, efi_width ( size
),
163 ( intptr_t ) io_addr
, count
,
164 ( void * ) data
) ) != 0 ) {
165 DBG ( "EFI I/O write at %p failed: %s\n",
166 io_addr
, efi_strerror ( efirc
) );
171 * Wait for I/O-mapped operation to complete
174 static void efi_iodelay ( void ) {
175 /* Write to non-existent port. Probably x86-only. */
179 PROVIDE_IOAPI_INLINE ( efi
, phys_to_bus
);
180 PROVIDE_IOAPI_INLINE ( efi
, bus_to_phys
);
181 PROVIDE_IOAPI_INLINE ( efi
, ioremap
);
182 PROVIDE_IOAPI_INLINE ( efi
, iounmap
);
183 PROVIDE_IOAPI_INLINE ( efi
, io_to_bus
);
184 PROVIDE_IOAPI_INLINE ( efi
, readb
);
185 PROVIDE_IOAPI_INLINE ( efi
, readw
);
186 PROVIDE_IOAPI_INLINE ( efi
, readl
);
187 PROVIDE_IOAPI_INLINE ( efi
, readq
);
188 PROVIDE_IOAPI_INLINE ( efi
, writeb
);
189 PROVIDE_IOAPI_INLINE ( efi
, writew
);
190 PROVIDE_IOAPI_INLINE ( efi
, writel
);
191 PROVIDE_IOAPI_INLINE ( efi
, writeq
);
192 PROVIDE_IOAPI_INLINE ( efi
, inb
);
193 PROVIDE_IOAPI_INLINE ( efi
, inw
);
194 PROVIDE_IOAPI_INLINE ( efi
, inl
);
195 PROVIDE_IOAPI_INLINE ( efi
, outb
);
196 PROVIDE_IOAPI_INLINE ( efi
, outw
);
197 PROVIDE_IOAPI_INLINE ( efi
, outl
);
198 PROVIDE_IOAPI_INLINE ( efi
, insb
);
199 PROVIDE_IOAPI_INLINE ( efi
, insw
);
200 PROVIDE_IOAPI_INLINE ( efi
, insl
);
201 PROVIDE_IOAPI_INLINE ( efi
, outsb
);
202 PROVIDE_IOAPI_INLINE ( efi
, outsw
);
203 PROVIDE_IOAPI_INLINE ( efi
, outsl
);
204 PROVIDE_IOAPI ( efi
, iodelay
, efi_iodelay
);
205 PROVIDE_IOAPI_INLINE ( efi
, mb
);