Patrick Georgi | ac95903 | 2020-05-05 22:49:26 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 2 | |
| 3 | #include <assert.h> |
Elyes HAOUAS | 6aaf7db | 2020-09-19 09:40:52 +0200 | [diff] [blame] | 4 | #include <console/console.h> |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 5 | #include <device/i2c_simple.h> |
| 6 | #include <gpio.h> |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 7 | #include <lib.h> |
| 8 | #include <soc/clock.h> |
| 9 | #include <soc/qcom_qup_se.h> |
Ravi Kumar Bokka | 34960d4 | 2021-07-27 21:02:54 +0530 | [diff] [blame] | 10 | #include <soc/qup_se_handlers_common.h> |
Rajesh Patil | 555c2d6 | 2021-06-16 14:13:00 +0530 | [diff] [blame] | 11 | #include <soc/qupv3_config_common.h> |
| 12 | #include <soc/qupv3_i2c_common.h> |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 13 | #include <stdint.h> |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 14 | |
| 15 | static void i2c_clk_configure(unsigned int bus, enum i2c_speed speed) |
| 16 | { |
| 17 | int clk_div = 0, t_high = 0, t_low = 0, t_cycle = 0; |
| 18 | struct qup_regs *regs = qup[bus].regs; |
| 19 | |
| 20 | switch (speed) { |
| 21 | case I2C_SPEED_STANDARD: |
| 22 | clk_div = 7; |
| 23 | t_high = 10; |
| 24 | t_low = 11; |
| 25 | t_cycle = 26; |
| 26 | break; |
| 27 | case I2C_SPEED_FAST: |
| 28 | clk_div = 2; |
| 29 | t_high = 5; |
| 30 | t_low = 12; |
| 31 | t_cycle = 24; |
| 32 | break; |
| 33 | case I2C_SPEED_FAST_PLUS: |
| 34 | clk_div = 1; |
| 35 | t_high = 3; |
| 36 | t_low = 9; |
| 37 | t_cycle = 18; |
| 38 | break; |
| 39 | default: |
| 40 | die("Unsupported I2C speed"); |
| 41 | } |
| 42 | |
| 43 | write32(®s->geni_ser_m_clk_cfg, (clk_div << 4) | 1); |
| 44 | /* Serial clock frequency is 19.2 MHz */ |
| 45 | write32(®s->i2c_scl_counters, ((t_high << 20) | (t_low << 10) |
| 46 | | t_cycle)); |
| 47 | } |
| 48 | |
| 49 | void i2c_init(unsigned int bus, enum i2c_speed speed) |
| 50 | { |
| 51 | uint32_t proto; |
| 52 | struct qup_regs *regs = qup[bus].regs; |
| 53 | |
| 54 | qupv3_se_fw_load_and_init(bus, SE_PROTOCOL_I2C, MIXED); |
| 55 | clock_enable_qup(bus); |
| 56 | i2c_clk_configure(bus, speed); |
| 57 | |
| 58 | proto = ((read32(®s->geni_fw_revision_ro) & |
| 59 | GENI_FW_REVISION_RO_PROTOCOL_MASK) >> |
| 60 | GENI_FW_REVISION_RO_PROTOCOL_SHIFT); |
| 61 | |
| 62 | assert(proto == 3); |
| 63 | |
| 64 | /* Serial engine IO initialization */ |
| 65 | write32(®s->geni_cgc_ctrl, DEFAULT_CGC_EN); |
| 66 | write32(®s->dma_general_cfg, |
| 67 | (AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CFG_ON |
| 68 | | DMA_TX_CLK_CGC_ON | DMA_RX_CLK_CGC_ON)); |
| 69 | write32(®s->geni_output_ctrl, |
| 70 | DEFAULT_IO_OUTPUT_CTRL_MSK); |
| 71 | write32(®s->geni_force_default_reg, FORCE_DEFAULT); |
| 72 | |
| 73 | /* Serial engine IO set mode */ |
| 74 | write32(®s->se_irq_en, (GENI_M_IRQ_EN | |
| 75 | GENI_S_IRQ_EN | DMA_TX_IRQ_EN | DMA_RX_IRQ_EN)); |
| 76 | write32(®s->se_gsi_event_en, 0); |
| 77 | |
| 78 | /* Set RX and RFR watermark */ |
| 79 | write32(®s->geni_rx_watermark_reg, 0); |
| 80 | write32(®s->geni_rx_rfr_watermark_reg, FIFO_DEPTH - 2); |
| 81 | |
| 82 | /* FIFO PACKING CONFIGURATION */ |
| 83 | write32(®s->geni_tx_packing_cfg0, PACK_VECTOR0 |
| 84 | | (PACK_VECTOR1 << 10)); |
| 85 | write32(®s->geni_tx_packing_cfg1, PACK_VECTOR2 |
| 86 | | (PACK_VECTOR3 << 10)); |
| 87 | write32(®s->geni_rx_packing_cfg0, PACK_VECTOR0 |
| 88 | | (PACK_VECTOR1 << 10)); |
| 89 | write32(®s->geni_rx_packing_cfg1, PACK_VECTOR2 |
| 90 | | (PACK_VECTOR3 << 10)); |
| 91 | write32(®s->geni_byte_granularity, (log2(BITS_PER_WORD) - 3)); |
| 92 | |
| 93 | /* GPIO Configuration */ |
| 94 | gpio_configure(qup[bus].pin[0], qup[bus].func[0], GPIO_PULL_UP, |
Ravi Kumar Bokka | a8e9dba | 2021-07-10 23:54:20 +0530 | [diff] [blame] | 95 | GPIO_2MA, GPIO_OUTPUT); |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 96 | gpio_configure(qup[bus].pin[1], qup[bus].func[1], GPIO_PULL_UP, |
Ravi Kumar Bokka | a8e9dba | 2021-07-10 23:54:20 +0530 | [diff] [blame] | 97 | GPIO_2MA, GPIO_OUTPUT); |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 98 | |
| 99 | /* Select and setup FIFO mode */ |
| 100 | write32(®s->geni_m_irq_clear, 0xFFFFFFFF); |
| 101 | write32(®s->geni_s_irq_clear, 0xFFFFFFFF); |
| 102 | write32(®s->dma_tx_irq_clr, 0xFFFFFFFF); |
| 103 | write32(®s->dma_rx_irq_clr, 0xFFFFFFFF); |
| 104 | write32(®s->geni_m_irq_enable, (M_COMMON_GENI_M_IRQ_EN | |
| 105 | M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN | |
| 106 | M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)); |
| 107 | write32(®s->geni_s_irq_enable, (S_COMMON_GENI_S_IRQ_EN |
| 108 | | S_CMD_DONE_EN)); |
| 109 | clrbits32(®s->geni_dma_mode_en, GENI_DMA_MODE_EN); |
| 110 | } |
| 111 | |
| 112 | static int i2c_do_xfer(unsigned int bus, struct i2c_msg segment, |
| 113 | unsigned int prams) |
| 114 | { |
| 115 | unsigned int cmd = (segment.flags & I2C_M_RD) ? 2 : 1; |
| 116 | unsigned int master_cmd_reg_val = (cmd << M_OPCODE_SHFT); |
| 117 | struct qup_regs *regs = qup[bus].regs; |
| 118 | void *dout = NULL, *din = NULL; |
Jes Klinke | 19baa9d | 2022-02-22 16:00:09 -0800 | [diff] [blame] | 119 | struct stopwatch timeout; |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 120 | |
| 121 | if (!(segment.flags & I2C_M_RD)) { |
| 122 | write32(®s->i2c_tx_trans_len, segment.len); |
| 123 | write32(®s->geni_tx_watermark_reg, TX_WATERMARK); |
| 124 | dout = segment.buf; |
| 125 | } else { |
| 126 | write32(®s->i2c_rx_trans_len, segment.len); |
| 127 | din = segment.buf; |
| 128 | } |
| 129 | |
| 130 | master_cmd_reg_val |= (prams & M_PARAMS_MSK); |
| 131 | write32(®s->geni_m_cmd0, master_cmd_reg_val); |
| 132 | |
Jes Klinke | 19baa9d | 2022-02-22 16:00:09 -0800 | [diff] [blame] | 133 | stopwatch_init_usecs_expire(&timeout, CONFIG_I2C_TRANSFER_TIMEOUT_US); |
| 134 | return qup_handle_transfer(bus, dout, din, segment.len, &timeout); |
satya priya | 52353d0 | 2019-09-19 16:45:18 +0530 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, |
| 138 | int seg_count) |
| 139 | { |
| 140 | struct i2c_msg *seg = segments; |
| 141 | int ret = 0; |
| 142 | |
| 143 | while (!ret && seg_count--) { |
| 144 | /* Stretch means end with repeated start, not stop */ |
| 145 | u32 stretch = (seg_count ? 1 : 0); |
| 146 | u32 m_param = 0; |
| 147 | |
| 148 | m_param |= (stretch << 2); |
| 149 | m_param |= ((seg->slave & 0x7F) << 9); |
| 150 | ret = i2c_do_xfer(bus, *seg, m_param); |
| 151 | seg++; |
| 152 | } |
| 153 | return ret; |
| 154 | } |