1 /* 2 * Copyright (c) 2025, MediaTek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <errno.h> 8 #include <stdint.h> 9 #include <string.h> 10 11 #include <lib/mmio.h> 12 #include <lib/spinlock.h> 13 14 #include <pmif.h> 15 #include "pmif_common.h" 16 #include "spmi_common.h" 17 #include "spmi_sw.h" 18 19 #define PMIF_CMD_REG_0 0 20 #define PMIF_CMD_REG 1 21 #define PMIF_CMD_EXT_REG 2 22 #define PMIF_CMD_EXT_REG_LONG 3 23 #define PMIF_READ_CMD_MIN 0x60 24 #define PMIF_READ_CMD_MAX 0x7F 25 #define PMIF_READ_CMD_EXT_MIN 0x20 26 #define PMIF_READ_CMD_EXT_MAX 0x2F 27 #define PMIF_READ_CMD_EXT_LONG_MIN 0x38 28 #define PMIF_READ_CMD_EXT_LONG_MAX 0x3F 29 #define PMIF_WRITE_CMD_MIN 0x40 30 #define PMIF_WRITE_CMD_MAX 0x5F 31 #define PMIF_WRITE_CMD_EXT_MAX 0xF 32 #define PMIF_WRITE_CMD_EXT_LONG_MIN 0x30 33 #define PMIF_WRITE_CMD_EXT_LONG_MAX 0x37 34 #define PMIF_WRITE_CMD_0_MIN 0x80 35 36 /* macro for SWINF_FSM */ 37 #define SWINF_FSM_IDLE 0x00 38 #define SWINF_FSM_REQ 0x02 39 #define SWINF_FSM_WFDLE 0x04 40 #define SWINF_FSM_WFVLDCLR 0x06 41 42 #define GET_SWINF_FSM(x) (((x) >> 1) & 0x7) 43 #define GET_PMIF_INIT_DONE(x) (((x) >> 15) & 0x1) 44 #define TIMEOUT_WAIT_IDLE_US 10000 /* 10ms */ 45 46 #define PMIF_RW_CMD_SET(opc, rw, sid, bc, addr) \ 47 (((opc) << 30) | ((rw) << 29) | ((sid) << 24) | ((bc) << 16) | (addr)) 48 49 static spinlock_t pmif_lock; 50 51 struct pmif *get_pmif_controller(int inf, int mstid) 52 { 53 return &pmif_spmi_arb[mstid]; 54 } 55 56 static int pmif_check_idle(int mstid) 57 { 58 struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); 59 unsigned int reg_rdata, offset = 0; 60 61 do { 62 offset = arb->regs[PMIF_SWINF_3_STA]; 63 reg_rdata = mmio_read_32((uintptr_t)(arb->base + offset)); 64 } while (GET_SWINF_FSM(reg_rdata) != SWINF_FSM_IDLE); 65 66 return 0; 67 } 68 69 static int pmif_check_vldclr(int mstid) 70 { 71 struct pmif *arb = get_pmif_controller(PMIF_SPMI, mstid); 72 unsigned int reg_rdata, offset = 0; 73 74 do { 75 offset = arb->regs[PMIF_SWINF_3_STA]; 76 reg_rdata = mmio_read_32((uintptr_t)(arb->base + offset)); 77 } while (GET_SWINF_FSM(reg_rdata) != SWINF_FSM_WFVLDCLR); 78 79 return 0; 80 } 81 82 int pmif_spmi_read_cmd(struct pmif *arb, uint8_t opc, uint8_t sid, 83 uint16_t addr, uint8_t *buf, uint8_t len) 84 { 85 int ret; 86 uint32_t offset = 0, data = 0; 87 uint8_t bc = len - 1; 88 89 if (sid > SPMI_MAX_SLAVE_ID || len > PMIF_BYTECNT_MAX) 90 return -EINVAL; 91 92 /* Check the opcode */ 93 if (opc >= PMIF_READ_CMD_MIN && opc <= PMIF_READ_CMD_MAX) 94 opc = PMIF_CMD_REG; 95 else if (opc >= PMIF_READ_CMD_EXT_MIN && opc <= PMIF_READ_CMD_EXT_MAX) 96 opc = PMIF_CMD_EXT_REG; 97 else if (opc >= PMIF_READ_CMD_EXT_LONG_MIN && opc <= PMIF_READ_CMD_EXT_LONG_MAX) 98 opc = PMIF_CMD_EXT_REG_LONG; 99 else 100 return -EINVAL; 101 102 spin_lock(&pmif_lock); 103 104 /* Wait for Software Interface FSM state to be IDLE. */ 105 ret = pmif_check_idle(arb->mstid); 106 if (ret) 107 goto done; 108 109 /* Send the command. */ 110 offset = arb->regs[PMIF_SWINF_3_ACC]; 111 mmio_write_32((uintptr_t)(arb->base + offset), PMIF_RW_CMD_SET(opc, 0, sid, bc, addr)); 112 /* 113 * Wait for Software Interface FSM state to be WFVLDCLR, 114 * read the data and clear the valid flag. 115 */ 116 ret = pmif_check_vldclr(arb->mstid); 117 if (ret) 118 goto done; 119 120 offset = arb->regs[PMIF_SWINF_3_RDATA_31_0]; 121 122 data = mmio_read_32((uintptr_t)(arb->base + offset)); 123 memcpy(buf, &data, (bc & 3) + 1); 124 125 offset = arb->regs[PMIF_SWINF_3_VLD_CLR]; 126 mmio_write_32((uintptr_t)(arb->base + offset), 0x1); 127 128 done: 129 spin_unlock(&pmif_lock); 130 return ret; 131 } 132 133 int pmif_spmi_write_cmd(struct pmif *arb, uint8_t opc, uint8_t sid, uint16_t addr, 134 const uint8_t *buf, uint8_t len) 135 { 136 int ret; 137 uint32_t offset = 0, data = 0; 138 uint8_t bc = len - 1; 139 140 if (sid > SPMI_MAX_SLAVE_ID || len > PMIF_BYTECNT_MAX) 141 return -EINVAL; 142 143 /* Check the opcode */ 144 if (opc >= PMIF_WRITE_CMD_MIN && opc <= PMIF_WRITE_CMD_MAX) 145 opc = PMIF_CMD_REG; 146 else if (opc <= PMIF_WRITE_CMD_EXT_MAX) 147 opc = PMIF_CMD_EXT_REG; 148 else if (opc >= PMIF_WRITE_CMD_EXT_LONG_MIN && opc <= PMIF_WRITE_CMD_EXT_LONG_MAX) 149 opc = PMIF_CMD_EXT_REG_LONG; 150 else if (opc >= PMIF_WRITE_CMD_0_MIN) 151 opc = PMIF_CMD_REG_0; 152 else 153 return -EINVAL; 154 155 spin_lock(&pmif_lock); 156 157 /* Wait for Software Interface FSM state to be IDLE. */ 158 ret = pmif_check_idle(arb->mstid); 159 if (ret) 160 goto done; 161 162 /* Set the write data. */ 163 offset = arb->regs[PMIF_SWINF_3_WDATA_31_0]; 164 memcpy(&data, buf, (bc & 3) + 1); 165 mmio_write_32((uintptr_t)(arb->base + offset), data); 166 /* Send the command. */ 167 offset = arb->regs[PMIF_SWINF_3_ACC]; 168 mmio_write_32((uintptr_t)(arb->base + offset), PMIF_RW_CMD_SET(opc, 1, sid, bc, addr)); 169 170 done: 171 spin_unlock(&pmif_lock); 172 return ret; 173 } 174