Elyes HAOUAS | 231b251 | 2020-05-07 07:29:44 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
T Michael Turney | cea0d9c | 2019-11-27 19:28:23 -0800 | [diff] [blame] | 2 | |
Elyes HAOUAS | 32661c7 | 2020-06-16 06:51:58 +0200 | [diff] [blame] | 3 | #include <cbfs.h> |
Elyes HAOUAS | 6aaf7db | 2020-09-19 09:40:52 +0200 | [diff] [blame] | 4 | #include <console/console.h> |
Elyes HAOUAS | 32661c7 | 2020-06-16 06:51:58 +0200 | [diff] [blame] | 5 | #include <string.h> |
T Michael Turney | cea0d9c | 2019-11-27 19:28:23 -0800 | [diff] [blame] | 6 | #include <soc/qupv3_config.h> |
| 7 | |
| 8 | static struct elf_se_hdr *fw_list[SE_PROTOCOL_MAX]; |
| 9 | |
| 10 | void qupv3_se_fw_load_and_init(unsigned int bus, unsigned int protocol, |
| 11 | unsigned int mode) |
| 12 | { |
| 13 | uint32_t i; |
| 14 | uint32_t reg_value; |
| 15 | const uint8_t *cfg_idx_arr; |
| 16 | const uint32_t *cfg_val_arr; |
| 17 | const uint32_t *fw_val_arr; |
| 18 | struct elf_se_hdr *hdr; |
| 19 | struct qup_regs *regs = qup[bus].regs; |
| 20 | static const char * const filename[] = { |
| 21 | [SE_PROTOCOL_SPI] = "fallback/spi_fw", |
| 22 | [SE_PROTOCOL_UART] = "fallback/uart_fw", |
| 23 | [SE_PROTOCOL_I2C] = "fallback/i2c_fw", |
| 24 | }; |
| 25 | |
| 26 | if (protocol >= SE_PROTOCOL_MAX || !filename[protocol]) |
| 27 | die("*ERROR* * INVALID PROTOCOL ***\n"); |
| 28 | |
| 29 | if (!fw_list[protocol]) { |
Julius Werner | 834b3ec | 2020-03-04 16:52:08 -0800 | [diff] [blame^] | 30 | fw_list[protocol] = cbfs_map(filename[protocol], NULL); |
T Michael Turney | cea0d9c | 2019-11-27 19:28:23 -0800 | [diff] [blame] | 31 | if (!fw_list[protocol]) |
Julius Werner | 834b3ec | 2020-03-04 16:52:08 -0800 | [diff] [blame^] | 32 | die("*ERROR* * cbfs_map() failed ***\n"); |
T Michael Turney | cea0d9c | 2019-11-27 19:28:23 -0800 | [diff] [blame] | 33 | } |
| 34 | |
| 35 | hdr = fw_list[protocol]; |
| 36 | assert(hdr->magic == SEFW_MAGIC_HEADER) |
| 37 | |
| 38 | cfg_idx_arr = (const uint8_t *)hdr + hdr->cfg_idx_offset; |
| 39 | cfg_val_arr = (const uint32_t *)((uint8_t *)hdr + hdr->cfg_val_offset); |
| 40 | fw_val_arr = (const uint32_t *)((uint8_t *)hdr + hdr->fw_offset); |
| 41 | |
| 42 | /* Unlock SE for FW loading */ |
| 43 | write32(®s->se_geni_fw_multilock_protns, 0x0); |
| 44 | write32(®s->se_geni_fw_multilock_msa, 0x0); |
| 45 | |
| 46 | /* First, ensure GENI FW is disabled */ |
| 47 | write32(®s->geni_output_ctrl, 0x0); |
| 48 | clrbits_le32(®s->geni_dfs_if_cfg, GENI_DFS_IF_CFG_DFS_IF_EN_BMSK); |
| 49 | setbits_le32(®s->geni_cgc_ctrl, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
| 50 | | GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); |
| 51 | write32(®s->se_geni_clk_ctrl, 0x0); |
| 52 | clrbits_le32(®s->geni_cgc_ctrl, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
| 53 | | GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); |
| 54 | |
T Michael Turney | cea0d9c | 2019-11-27 19:28:23 -0800 | [diff] [blame] | 55 | /* HPG section 3.1.7.1 */ |
Roja Rani Yarubandi | dcf80ab0 | 2020-05-07 16:28:29 +0530 | [diff] [blame] | 56 | if (protocol != SE_PROTOCOL_UART) { |
T Michael Turney | cea0d9c | 2019-11-27 19:28:23 -0800 | [diff] [blame] | 57 | setbits_le32(®s->geni_dfs_if_cfg, |
| 58 | GENI_DFS_IF_CFG_DFS_IF_EN_BMSK); |
| 59 | /* configure clock dfsr */ |
| 60 | clock_configure_dfsr(bus); |
| 61 | } |
| 62 | |
| 63 | /* HPG section 3.1.7.2 */ |
| 64 | /* No Init Required */ |
| 65 | |
| 66 | /* HPG section 3.1.7.3 */ |
| 67 | write32(®s->dma_general_cfg, |
| 68 | DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK | |
| 69 | DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK | |
| 70 | DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK | |
| 71 | DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK); |
| 72 | write32(®s->geni_cgc_ctrl, DEFAULT_CGC_EN); |
| 73 | |
| 74 | /* HPG section 3.1.7.4 */ |
| 75 | write32(®s->geni_init_cfg_revision, hdr->cfg_version); |
| 76 | write32(®s->geni_s_init_cfg_revision, hdr->cfg_version); |
| 77 | |
| 78 | assert(cfg_idx_arr[hdr->cfg_size_in_items - 1] * sizeof(uint32_t) <= |
| 79 | MAX_OFFSET_CFG_REG); |
| 80 | |
| 81 | for (i = 0; i < hdr->cfg_size_in_items; i++) { |
| 82 | write32(®s->geni_cfg_reg0 + cfg_idx_arr[i], |
| 83 | cfg_val_arr[i]); |
| 84 | } |
| 85 | |
| 86 | /* HPG section 3.1.7.9 */ |
| 87 | /* non-UART configuration, UART driver can configure as desired for UART |
| 88 | */ |
| 89 | write32(®s->geni_rx_rfr_watermark_reg, FIFO_DEPTH - 2); |
| 90 | |
| 91 | /* HPG section 3.1.7.5 */ |
| 92 | /* Don't change any SPI polarity, client driver will handle this */ |
| 93 | setbits_le32(®s->geni_output_ctrl, DEFAULT_IO_OUTPUT_CTRL_MSK); |
| 94 | |
| 95 | /* HPG section 3.1.7.6 */ |
| 96 | reg_value = read32(®s->geni_dma_mode_en); |
| 97 | if (mode == GSI) { |
| 98 | reg_value |= GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK; |
| 99 | write32(®s->geni_dma_mode_en, reg_value); |
| 100 | write32(®s->se_irq_en, 0x0); |
| 101 | write32(®s->se_gsi_event_en, SE_GSI_EVENT_EN_BMSK); |
| 102 | } else if (mode == FIFO) { |
| 103 | reg_value &= ~GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK; |
| 104 | write32(®s->geni_dma_mode_en, reg_value); |
| 105 | write32(®s->se_irq_en, SE_IRQ_EN_RMSK); |
| 106 | write32(®s->se_gsi_event_en, 0x0); |
| 107 | } else if (mode == CPU_DMA) { |
| 108 | reg_value |= GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK; |
| 109 | write32(®s->geni_dma_mode_en, reg_value); |
| 110 | write32(®s->se_irq_en, SE_IRQ_EN_RMSK); |
| 111 | write32(®s->se_gsi_event_en, 0x0); |
| 112 | } |
| 113 | |
| 114 | /* HPG section 3.1.7.7 */ |
| 115 | write32(®s->geni_m_irq_enable, |
| 116 | M_COMMON_GENI_M_IRQ_EN); |
| 117 | reg_value = S_CMD_OVERRUN_EN | S_ILLEGAL_CMD_EN | |
| 118 | S_CMD_CANCEL_EN | S_CMD_ABORT_EN | |
| 119 | S_GP_IRQ_0_EN | S_GP_IRQ_1_EN | |
| 120 | S_GP_IRQ_2_EN | S_GP_IRQ_3_EN | |
| 121 | S_RX_FIFO_WR_ERR_EN | S_RX_FIFO_RD_ERR_EN; |
| 122 | write32(®s->geni_s_irq_enable, reg_value); |
| 123 | |
| 124 | /* HPG section 3.1.7.8 */ |
| 125 | /* GPI/DMA mode */ |
| 126 | reg_value = DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK | |
| 127 | DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK | |
| 128 | DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK; |
| 129 | write32(®s->dma_tx_irq_en_set, reg_value); |
| 130 | |
| 131 | reg_value = DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK | |
| 132 | DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK | |
| 133 | DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK | |
| 134 | DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK; |
| 135 | write32(®s->dma_rx_irq_en_set, reg_value); |
| 136 | |
| 137 | /* HPG section 3.1.7.10 */ |
| 138 | reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) | |
| 139 | (hdr->fw_version & 0xFF << |
| 140 | FW_REV_VERSION_SHFT); |
| 141 | write32(®s->se_geni_fw_revision, reg_value); |
| 142 | |
| 143 | reg_value = |
| 144 | (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) | |
| 145 | (hdr->fw_version & 0xFF << |
| 146 | FW_REV_VERSION_SHFT); |
| 147 | write32(®s->se_s_fw_revision, reg_value); |
| 148 | |
| 149 | assert(hdr->fw_size_in_items <= SIZE_GENI_FW_RAM); |
| 150 | |
| 151 | memcpy((®s->se_geni_cfg_ramn), fw_val_arr, |
| 152 | hdr->fw_size_in_items * sizeof(uint32_t)); |
| 153 | |
| 154 | /* HPG section 3.1.7.12 */ |
| 155 | write32(®s->geni_force_default_reg, 0x1); |
| 156 | setbits_le32(®s->geni_cgc_ctrl, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
| 157 | |GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); |
| 158 | setbits_le32(®s->se_geni_clk_ctrl, GENI_CLK_CTRL_SER_CLK_SEL_BMSK); |
| 159 | clrbits_le32(®s->geni_cgc_ctrl, |
| 160 | (GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | |
| 161 | GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK)); |
| 162 | |
| 163 | /* HPG section 3.1.7.13 */ |
| 164 | /* GSI/DMA mode */ |
| 165 | setbits_le32(®s->se_dma_if_en, DMA_IF_EN_DMA_IF_EN_BMSK); |
| 166 | |
| 167 | /* HPG section 3.1.7.14 */ |
| 168 | reg_value = read32(®s->se_fifo_if_disable); |
| 169 | if ((mode == MIXED) || (mode == FIFO)) |
| 170 | reg_value &= ~FIFO_IF_DISABLE; |
| 171 | else |
| 172 | reg_value |= FIFO_IF_DISABLE; |
| 173 | write32(®s->se_fifo_if_disable, reg_value); |
| 174 | write32(®s->se_geni_clk_ctrl, 0x1); |
| 175 | |
| 176 | /* Lock SE from FW loading */ |
| 177 | write32(®s->se_geni_fw_multilock_protns, 0x1); |
| 178 | write32(®s->se_geni_fw_multilock_msa, 0x1); |
| 179 | } |
| 180 | |
| 181 | static void qup_common_init(int addr) |
| 182 | { |
| 183 | struct qupv3_common_reg *qupv3_common; |
| 184 | /* HPG section 3.1.2 */ |
| 185 | qupv3_common = (struct qupv3_common_reg *)(uintptr_t) addr; |
| 186 | setbits32(&qupv3_common->qupv3_common_cfg_reg, |
| 187 | QUPV3_COMMON_CFG_FAST_SWITCH_TO_HIGH_DISABLE_BMSK); |
| 188 | |
| 189 | /* HPG section 3.1.7.3 */ |
| 190 | setbits32(&qupv3_common->qupv3_se_ahb_m_cfg_reg, |
| 191 | QUPV3_SE_AHB_M_CFG_AHB_M_CLK_CGC_ON_BMSK); |
| 192 | } |
| 193 | |
| 194 | void qupv3_fw_init(void) |
| 195 | { |
| 196 | uint8_t i; |
| 197 | |
| 198 | /* Turn on all QUP clocks */ |
| 199 | for (i = 0; i < QUPV3_SE_MAX; i++) |
| 200 | clock_enable_qup(i); |
| 201 | |
| 202 | qup_common_init(QUP_WRAP0_BASE); |
| 203 | qup_common_init(QUP_WRAP1_BASE); |
| 204 | } |