1 /* 2 * Copyright (c) 2020, Google LLC. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <common/debug.h> 8 #include <drivers/delay_timer.h> 9 #include <lib/mmio.h> 10 11 #include <spmi_arb.h> 12 13 #define REG_APID_MAP(apid) (0x0C440900U + sizeof(uint32_t) * apid) 14 #define NUM_APID ((0x1100U - 0x900U) / sizeof(uint32_t)) 15 16 #define PPID_MASK (0xfffU << 8) 17 18 #define REG_ARB_CMD(apid) (0x0C600000U + 0x10000U * apid) 19 /* These are opcodes specific to this SPMI arbitrator, *not* SPMI commands. */ 20 #define OPC_EXT_WRITEL 0 21 #define OPC_EXT_READL 1 22 23 #define REG_ARB_STATUS(apid) (0x0C600008U + 0x10000U * apid) 24 #define ARB_STATUS_DONE BIT(0) 25 #define ARB_STATUS_FAILURE BIT(1) 26 #define ARB_STATUS_DENIED BIT(2) 27 #define ARB_STATUS_DROPPED BIT(3) 28 29 /* Fake status to report driver errors. */ 30 #define ARB_FAKE_STATUS_TIMEOUT BIT(8) 31 32 #define REG_ARB_RDATA0(apid) (0x0C600018U + 0x10000U * apid) 33 #define REG_ARB_WDATA0(apid) (0x0C600010U + 0x10000U * apid) 34 35 static int addr_to_apid(uint32_t addr) 36 { 37 unsigned int i; 38 39 for (i = 0U; i < NUM_APID; i++) { 40 uint32_t reg = mmio_read_32(REG_APID_MAP(i)); 41 if ((reg != 0U) && ((addr & PPID_MASK) == (reg & PPID_MASK))) { 42 return i; 43 } 44 } 45 46 return -1; 47 } 48 49 static int wait_for_done(uint16_t apid) 50 { 51 unsigned int timeout = 100; 52 53 while (timeout-- != 0U) { 54 uint32_t status = mmio_read_32(REG_ARB_STATUS(apid)); 55 if ((status & ARB_STATUS_DONE) != 0U) { 56 if ((status & ARB_STATUS_FAILURE) != 0U || 57 (status & ARB_STATUS_DENIED) != 0U || 58 (status & ARB_STATUS_DROPPED) != 0U) { 59 return status & 0xff; 60 } 61 return 0; 62 } 63 mdelay(1); 64 } 65 ERROR("SPMI_ARB timeout!\n"); 66 return ARB_FAKE_STATUS_TIMEOUT; 67 } 68 69 static void arb_command(uint16_t apid, uint8_t opcode, uint32_t addr, 70 uint8_t bytes) 71 { 72 mmio_write_32(REG_ARB_CMD(apid), (uint32_t)opcode << 27 | 73 (addr & 0xff) << 4 | (bytes - 1)); 74 } 75 76 int spmi_arb_read8(uint32_t addr) 77 { 78 int apid = addr_to_apid(addr); 79 80 if (apid < 0) { 81 return apid; 82 } 83 84 arb_command(apid, OPC_EXT_READL, addr, 1); 85 86 int ret = wait_for_done(apid); 87 if (ret != 0) { 88 ERROR("SPMI_ARB read error [0x%x]: 0x%x\n", addr, ret); 89 return ret; 90 } 91 92 return mmio_read_32(REG_ARB_RDATA0(apid)) & 0xff; 93 } 94 95 int spmi_arb_write8(uint32_t addr, uint8_t data) 96 { 97 int apid = addr_to_apid(addr); 98 99 if (apid < 0) { 100 return apid; 101 } 102 103 mmio_write_32(REG_ARB_WDATA0(apid), data); 104 arb_command(apid, OPC_EXT_WRITEL, addr, 1); 105 106 int ret = wait_for_done(apid); 107 if (ret != 0) { 108 ERROR("SPMI_ARB write error [0x%x] = 0x%x: 0x%x\n", 109 addr, data, ret); 110 } 111 112 return ret; 113 } 114