Angel Pons | 2178b72 | 2020-05-31 00:55:35 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #include <console/console.h> |
| 4 | #include <delay.h> |
| 5 | #include "pch.h" |
| 6 | #include "iobp.h" |
| 7 | |
| 8 | #define IOBP_RETRY 1000 |
| 9 | |
| 10 | static inline int iobp_poll(void) |
| 11 | { |
| 12 | unsigned int try; |
| 13 | |
| 14 | for (try = IOBP_RETRY; try > 0; try--) { |
| 15 | u16 status = RCBA16(IOBPS); |
| 16 | if ((status & IOBPS_READY) == 0) |
| 17 | return 1; |
| 18 | udelay(10); |
| 19 | } |
| 20 | |
| 21 | printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n"); |
| 22 | return 0; |
| 23 | } |
| 24 | |
| 25 | u32 pch_iobp_read(u32 address) |
| 26 | { |
| 27 | u16 status; |
| 28 | |
| 29 | if (!iobp_poll()) |
| 30 | return 0; |
| 31 | |
| 32 | /* Set the address */ |
| 33 | RCBA32(IOBPIRI) = address; |
| 34 | |
| 35 | /* READ OPCODE */ |
| 36 | status = RCBA16(IOBPS); |
| 37 | status &= ~IOBPS_MASK; |
| 38 | status |= IOBPS_READ; |
| 39 | RCBA16(IOBPS) = status; |
| 40 | |
| 41 | /* Undocumented magic */ |
| 42 | RCBA16(IOBPU) = IOBPU_MAGIC; |
| 43 | |
| 44 | /* Set ready bit */ |
| 45 | status = RCBA16(IOBPS); |
| 46 | status |= IOBPS_READY; |
| 47 | RCBA16(IOBPS) = status; |
| 48 | |
| 49 | if (!iobp_poll()) |
| 50 | return 0; |
| 51 | |
| 52 | /* Check for successful transaction */ |
| 53 | status = RCBA16(IOBPS); |
| 54 | if (status & IOBPS_TX_MASK) { |
| 55 | printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address); |
| 56 | return 0; |
| 57 | } |
| 58 | |
| 59 | /* Read IOBP data */ |
| 60 | return RCBA32(IOBPD); |
| 61 | } |
| 62 | |
| 63 | void pch_iobp_write(u32 address, u32 data) |
| 64 | { |
| 65 | u16 status; |
| 66 | |
| 67 | if (!iobp_poll()) |
| 68 | return; |
| 69 | |
| 70 | /* Set the address */ |
| 71 | RCBA32(IOBPIRI) = address; |
| 72 | |
| 73 | /* WRITE OPCODE */ |
| 74 | status = RCBA16(IOBPS); |
| 75 | status &= ~IOBPS_MASK; |
| 76 | status |= IOBPS_WRITE; |
| 77 | RCBA16(IOBPS) = status; |
| 78 | |
| 79 | RCBA32(IOBPD) = data; |
| 80 | |
| 81 | /* Undocumented magic */ |
| 82 | RCBA16(IOBPU) = IOBPU_MAGIC; |
| 83 | |
| 84 | /* Set ready bit */ |
| 85 | status = RCBA16(IOBPS); |
| 86 | status |= IOBPS_READY; |
| 87 | RCBA16(IOBPS) = status; |
| 88 | |
| 89 | if (!iobp_poll()) |
| 90 | return; |
| 91 | |
| 92 | /* Check for successful transaction */ |
| 93 | status = RCBA16(IOBPS); |
| 94 | if (status & IOBPS_TX_MASK) { |
| 95 | printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address); |
| 96 | return; |
| 97 | } |
| 98 | |
Angel Pons | 83b33f6 | 2020-09-25 00:58:07 +0200 | [diff] [blame] | 99 | printk(BIOS_SPEW, "IOBP: set 0x%08x to 0x%08x\n", address, data); |
Angel Pons | 2178b72 | 2020-05-31 00:55:35 +0200 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue) |
| 103 | { |
| 104 | u32 data = pch_iobp_read(address); |
| 105 | |
| 106 | /* Update the data */ |
| 107 | data &= andvalue; |
| 108 | data |= orvalue; |
| 109 | |
| 110 | pch_iobp_write(address, data); |
| 111 | } |
Angel Pons | dfb29fd | 2021-04-19 15:58:21 +0200 | [diff] [blame] | 112 | |
| 113 | void pch_iobp_exec(u32 addr, u16 op_code, u8 route_id, u32 *data, u8 *resp) |
| 114 | { |
| 115 | if (!data || !resp) |
| 116 | return; |
| 117 | |
| 118 | *resp = -1; |
| 119 | if (!iobp_poll()) |
| 120 | return; |
| 121 | |
| 122 | /* RCBA2330[31:0] = Address */ |
| 123 | RCBA32(IOBPIRI) = addr; |
| 124 | /* RCBA2338[15:8] = opcode */ |
| 125 | RCBA16(IOBPS) = (RCBA16(IOBPS) & 0x00ff) | op_code; |
| 126 | /* RCBA233A[15:8] = 0xf0 RCBA233A[7:0] = Route ID */ |
| 127 | RCBA16(IOBPU) = IOBPU_MAGIC | route_id; |
| 128 | |
| 129 | if (op_code == IOBP_PCICFG_WRITE) |
| 130 | RCBA32(IOBPD) = *data; |
| 131 | /* Set RCBA2338[0] to trigger IOBP transaction*/ |
| 132 | RCBA16(IOBPS) = RCBA16(IOBPS) | 0x1; |
| 133 | |
| 134 | if (!iobp_poll()) |
| 135 | return; |
| 136 | |
| 137 | *resp = (RCBA16(IOBPS) & IOBPS_TX_MASK) >> 1; |
| 138 | *data = RCBA32(IOBPD); |
| 139 | } |