1 /* SPDX-License-Identifier: GPL-2.0-only */
11 ACCESS_TYPE_BYTE
= 0x0,
13 ACCESS_TYPE_WORD
= 0x1,
15 ACCESS_TYPE_LONG
= 0x2,
17 * 32-bit access, read or write of MEC_EMI_EC_DATA_B3 causes the
18 * EC data register to be incremented.
20 ACCESS_TYPE_LONG_AUTO_INCREMENT
= 0x3,
23 /* EMI registers are relative to base */
24 #define MEC_EMI_HOST_TO_EC(base) ((base) + 0)
25 #define MEC_EMI_EC_TO_HOST(base) ((base) + 1)
26 #define MEC_EMI_EC_ADDRESS_B0(base) ((base) + 2)
27 #define MEC_EMI_EC_ADDRESS_B1(base) ((base) + 3)
28 #define MEC_EMI_EC_DATA_B0(base) ((base) + 4)
29 #define MEC_EMI_EC_DATA_B1(base) ((base) + 5)
30 #define MEC_EMI_EC_DATA_B2(base) ((base) + 6)
31 #define MEC_EMI_EC_DATA_B3(base) ((base) + 7)
34 * cros_ec_lpc_mec_emi_write_address
36 * Initialize EMI read / write at a given address.
38 * @base: Starting read / write address
39 * @offset: Offset applied to base address
40 * @access_mode: Type of access, typically 32-bit auto-increment
42 static void mec_emi_write_address(uint16_t base
, uint16_t offset
,
43 enum mec_access_mode access_mode
)
45 outb((offset
& 0xfc) | access_mode
, MEC_EMI_EC_ADDRESS_B0(base
));
46 outb((offset
>> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1(base
));
49 uint8_t mec_io_bytes(enum mec_io_type type
, uint16_t base
,
50 uint16_t offset
, void *buffer
, size_t size
)
52 enum mec_access_mode access_mode
, new_access_mode
;
53 uint8_t *buf
= buffer
;
58 if (size
== 0 || base
== 0)
62 * Long access cannot be used on misaligned data since reading B0 loads
63 * the data register and writing B3 flushes it.
65 if ((offset
& 0x3) || (size
< 4))
66 access_mode
= ACCESS_TYPE_BYTE
;
68 access_mode
= ACCESS_TYPE_LONG_AUTO_INCREMENT
;
70 /* Initialize I/O at desired address */
71 mec_emi_write_address(base
, offset
, access_mode
);
73 /* Skip bytes in case of misaligned offset */
74 io_addr
= MEC_EMI_EC_DATA_B0(base
) + (offset
& 0x3);
76 while (io_addr
<= MEC_EMI_EC_DATA_B3(base
)) {
77 if (type
== MEC_IO_WRITE
)
78 outb(buf
[i
], io_addr
++);
80 buf
[i
] = inb(io_addr
++);
85 /* Extra bounds check in case of misaligned size */
91 * Use long auto-increment access except for misaligned write,
92 * since writing B3 triggers the flush.
94 if ((size
- i
) < 4 && type
== MEC_IO_WRITE
)
95 new_access_mode
= ACCESS_TYPE_BYTE
;
97 new_access_mode
= ACCESS_TYPE_LONG_AUTO_INCREMENT
;
98 if (new_access_mode
!= access_mode
||
99 access_mode
!= ACCESS_TYPE_LONG_AUTO_INCREMENT
) {
100 access_mode
= new_access_mode
;
101 mec_emi_write_address(base
, offset
, access_mode
);
104 /* Access [B0, B3] on each loop pass */
105 io_addr
= MEC_EMI_EC_DATA_B0(base
);