Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2016-2018 Linaro Ltd.
0004  * Copyright (C) 2014 Sony Mobile Communications AB
0005  * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
0006  */
0007 #include <linux/clk.h>
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/iopoll.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/module.h>
0014 #include <linux/of_address.h>
0015 #include <linux/of_reserved_mem.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018 #include <linux/regulator/consumer.h>
0019 #include <linux/reset.h>
0020 #include <linux/soc/qcom/mdt_loader.h>
0021 #include "qcom_common.h"
0022 #include "qcom_pil_info.h"
0023 #include "qcom_q6v5.h"
0024 
0025 #define WCSS_CRASH_REASON       421
0026 
0027 /* Q6SS Register Offsets */
0028 #define Q6SS_RESET_REG      0x014
0029 #define Q6SS_GFMUX_CTL_REG      0x020
0030 #define Q6SS_PWR_CTL_REG        0x030
0031 #define Q6SS_MEM_PWR_CTL        0x0B0
0032 #define Q6SS_STRAP_ACC          0x110
0033 #define Q6SS_CGC_OVERRIDE       0x034
0034 #define Q6SS_BCR_REG            0x6000
0035 
0036 /* AXI Halt Register Offsets */
0037 #define AXI_HALTREQ_REG         0x0
0038 #define AXI_HALTACK_REG         0x4
0039 #define AXI_IDLE_REG            0x8
0040 
0041 #define HALT_ACK_TIMEOUT_MS     100
0042 
0043 /* Q6SS_RESET */
0044 #define Q6SS_STOP_CORE          BIT(0)
0045 #define Q6SS_CORE_ARES          BIT(1)
0046 #define Q6SS_BUS_ARES_ENABLE        BIT(2)
0047 
0048 /* Q6SS_BRC_RESET */
0049 #define Q6SS_BRC_BLK_ARES       BIT(0)
0050 
0051 /* Q6SS_GFMUX_CTL */
0052 #define Q6SS_CLK_ENABLE         BIT(1)
0053 #define Q6SS_SWITCH_CLK_SRC     BIT(8)
0054 
0055 /* Q6SS_PWR_CTL */
0056 #define Q6SS_L2DATA_STBY_N      BIT(18)
0057 #define Q6SS_SLP_RET_N          BIT(19)
0058 #define Q6SS_CLAMP_IO           BIT(20)
0059 #define QDSS_BHS_ON         BIT(21)
0060 #define QDSS_Q6_MEMORIES        GENMASK(15, 0)
0061 
0062 /* Q6SS parameters */
0063 #define Q6SS_LDO_BYP        BIT(25)
0064 #define Q6SS_BHS_ON     BIT(24)
0065 #define Q6SS_CLAMP_WL       BIT(21)
0066 #define Q6SS_CLAMP_QMC_MEM      BIT(22)
0067 #define HALT_CHECK_MAX_LOOPS        200
0068 #define Q6SS_XO_CBCR        GENMASK(5, 3)
0069 #define Q6SS_SLEEP_CBCR     GENMASK(5, 2)
0070 
0071 /* Q6SS config/status registers */
0072 #define TCSR_GLOBAL_CFG0    0x0
0073 #define TCSR_GLOBAL_CFG1    0x4
0074 #define SSCAON_CONFIG       0x8
0075 #define SSCAON_STATUS       0xc
0076 #define Q6SS_BHS_STATUS     0x78
0077 #define Q6SS_RST_EVB        0x10
0078 
0079 #define BHS_EN_REST_ACK     BIT(0)
0080 #define SSCAON_ENABLE       BIT(13)
0081 #define SSCAON_BUS_EN       BIT(15)
0082 #define SSCAON_BUS_MUX_MASK GENMASK(18, 16)
0083 
0084 #define MEM_BANKS       19
0085 #define TCSR_WCSS_CLK_MASK  0x1F
0086 #define TCSR_WCSS_CLK_ENABLE    0x14
0087 
0088 #define MAX_HALT_REG        3
0089 enum {
0090     WCSS_IPQ8074,
0091     WCSS_QCS404,
0092 };
0093 
0094 struct wcss_data {
0095     const char *firmware_name;
0096     unsigned int crash_reason_smem;
0097     u32 version;
0098     bool aon_reset_required;
0099     bool wcss_q6_reset_required;
0100     const char *ssr_name;
0101     const char *sysmon_name;
0102     int ssctl_id;
0103     const struct rproc_ops *ops;
0104     bool requires_force_stop;
0105 };
0106 
0107 struct q6v5_wcss {
0108     struct device *dev;
0109 
0110     void __iomem *reg_base;
0111     void __iomem *rmb_base;
0112 
0113     struct regmap *halt_map;
0114     u32 halt_q6;
0115     u32 halt_wcss;
0116     u32 halt_nc;
0117 
0118     struct clk *xo;
0119     struct clk *ahbfabric_cbcr_clk;
0120     struct clk *gcc_abhs_cbcr;
0121     struct clk *gcc_axim_cbcr;
0122     struct clk *lcc_csr_cbcr;
0123     struct clk *ahbs_cbcr;
0124     struct clk *tcm_slave_cbcr;
0125     struct clk *qdsp6ss_abhm_cbcr;
0126     struct clk *qdsp6ss_sleep_cbcr;
0127     struct clk *qdsp6ss_axim_cbcr;
0128     struct clk *qdsp6ss_xo_cbcr;
0129     struct clk *qdsp6ss_core_gfmux;
0130     struct clk *lcc_bcr_sleep;
0131     struct regulator *cx_supply;
0132     struct qcom_sysmon *sysmon;
0133 
0134     struct reset_control *wcss_aon_reset;
0135     struct reset_control *wcss_reset;
0136     struct reset_control *wcss_q6_reset;
0137     struct reset_control *wcss_q6_bcr_reset;
0138 
0139     struct qcom_q6v5 q6v5;
0140 
0141     phys_addr_t mem_phys;
0142     phys_addr_t mem_reloc;
0143     void *mem_region;
0144     size_t mem_size;
0145 
0146     unsigned int crash_reason_smem;
0147     u32 version;
0148     bool requires_force_stop;
0149 
0150     struct qcom_rproc_glink glink_subdev;
0151     struct qcom_rproc_ssr ssr_subdev;
0152 };
0153 
0154 static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
0155 {
0156     int ret;
0157     u32 val;
0158     int i;
0159 
0160     /* Assert resets, stop core */
0161     val = readl(wcss->reg_base + Q6SS_RESET_REG);
0162     val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
0163     writel(val, wcss->reg_base + Q6SS_RESET_REG);
0164 
0165     /* BHS require xo cbcr to be enabled */
0166     val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0167     val |= 0x1;
0168     writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0169 
0170     /* Read CLKOFF bit to go low indicating CLK is enabled */
0171     ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
0172                  val, !(val & BIT(31)), 1,
0173                  HALT_CHECK_MAX_LOOPS);
0174     if (ret) {
0175         dev_err(wcss->dev,
0176             "xo cbcr enabling timed out (rc:%d)\n", ret);
0177         return ret;
0178     }
0179     /* Enable power block headswitch and wait for it to stabilize */
0180     val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0181     val |= Q6SS_BHS_ON;
0182     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0183     udelay(1);
0184 
0185     /* Put LDO in bypass mode */
0186     val |= Q6SS_LDO_BYP;
0187     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0188 
0189     /* Deassert Q6 compiler memory clamp */
0190     val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0191     val &= ~Q6SS_CLAMP_QMC_MEM;
0192     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0193 
0194     /* Deassert memory peripheral sleep and L2 memory standby */
0195     val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
0196     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0197 
0198     /* Turn on L1, L2, ETB and JU memories 1 at a time */
0199     val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
0200     for (i = MEM_BANKS; i >= 0; i--) {
0201         val |= BIT(i);
0202         writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
0203         /*
0204          * Read back value to ensure the write is done then
0205          * wait for 1us for both memory peripheral and data
0206          * array to turn on.
0207          */
0208         val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
0209         udelay(1);
0210     }
0211     /* Remove word line clamp */
0212     val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0213     val &= ~Q6SS_CLAMP_WL;
0214     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0215 
0216     /* Remove IO clamp */
0217     val &= ~Q6SS_CLAMP_IO;
0218     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0219 
0220     /* Bring core out of reset */
0221     val = readl(wcss->reg_base + Q6SS_RESET_REG);
0222     val &= ~Q6SS_CORE_ARES;
0223     writel(val, wcss->reg_base + Q6SS_RESET_REG);
0224 
0225     /* Turn on core clock */
0226     val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0227     val |= Q6SS_CLK_ENABLE;
0228     writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0229 
0230     /* Start core execution */
0231     val = readl(wcss->reg_base + Q6SS_RESET_REG);
0232     val &= ~Q6SS_STOP_CORE;
0233     writel(val, wcss->reg_base + Q6SS_RESET_REG);
0234 
0235     return 0;
0236 }
0237 
0238 static int q6v5_wcss_start(struct rproc *rproc)
0239 {
0240     struct q6v5_wcss *wcss = rproc->priv;
0241     int ret;
0242 
0243     qcom_q6v5_prepare(&wcss->q6v5);
0244 
0245     /* Release Q6 and WCSS reset */
0246     ret = reset_control_deassert(wcss->wcss_reset);
0247     if (ret) {
0248         dev_err(wcss->dev, "wcss_reset failed\n");
0249         return ret;
0250     }
0251 
0252     ret = reset_control_deassert(wcss->wcss_q6_reset);
0253     if (ret) {
0254         dev_err(wcss->dev, "wcss_q6_reset failed\n");
0255         goto wcss_reset;
0256     }
0257 
0258     /* Lithium configuration - clock gating and bus arbitration */
0259     ret = regmap_update_bits(wcss->halt_map,
0260                  wcss->halt_nc + TCSR_GLOBAL_CFG0,
0261                  TCSR_WCSS_CLK_MASK,
0262                  TCSR_WCSS_CLK_ENABLE);
0263     if (ret)
0264         goto wcss_q6_reset;
0265 
0266     ret = regmap_update_bits(wcss->halt_map,
0267                  wcss->halt_nc + TCSR_GLOBAL_CFG1,
0268                  1, 0);
0269     if (ret)
0270         goto wcss_q6_reset;
0271 
0272     /* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
0273     writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
0274 
0275     ret = q6v5_wcss_reset(wcss);
0276     if (ret)
0277         goto wcss_q6_reset;
0278 
0279     ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
0280     if (ret == -ETIMEDOUT)
0281         dev_err(wcss->dev, "start timed out\n");
0282 
0283     return ret;
0284 
0285 wcss_q6_reset:
0286     reset_control_assert(wcss->wcss_q6_reset);
0287 
0288 wcss_reset:
0289     reset_control_assert(wcss->wcss_reset);
0290 
0291     return ret;
0292 }
0293 
0294 static int q6v5_wcss_qcs404_power_on(struct q6v5_wcss *wcss)
0295 {
0296     unsigned long val;
0297     int ret, idx;
0298 
0299     /* Toggle the restart */
0300     reset_control_assert(wcss->wcss_reset);
0301     usleep_range(200, 300);
0302     reset_control_deassert(wcss->wcss_reset);
0303     usleep_range(200, 300);
0304 
0305     /* Enable GCC_WDSP_Q6SS_AHBS_CBCR clock */
0306     ret = clk_prepare_enable(wcss->gcc_abhs_cbcr);
0307     if (ret)
0308         return ret;
0309 
0310     /* Remove reset to the WCNSS QDSP6SS */
0311     reset_control_deassert(wcss->wcss_q6_bcr_reset);
0312 
0313     /* Enable Q6SSTOP_AHBFABRIC_CBCR clock */
0314     ret = clk_prepare_enable(wcss->ahbfabric_cbcr_clk);
0315     if (ret)
0316         goto disable_gcc_abhs_cbcr_clk;
0317 
0318     /* Enable the LCCCSR CBC clock, Q6SSTOP_Q6SSTOP_LCC_CSR_CBCR clock */
0319     ret = clk_prepare_enable(wcss->lcc_csr_cbcr);
0320     if (ret)
0321         goto disable_ahbfabric_cbcr_clk;
0322 
0323     /* Enable the Q6AHBS CBC, Q6SSTOP_Q6SS_AHBS_CBCR clock */
0324     ret = clk_prepare_enable(wcss->ahbs_cbcr);
0325     if (ret)
0326         goto disable_csr_cbcr_clk;
0327 
0328     /* Enable the TCM slave CBC, Q6SSTOP_Q6SS_TCM_SLAVE_CBCR clock */
0329     ret = clk_prepare_enable(wcss->tcm_slave_cbcr);
0330     if (ret)
0331         goto disable_ahbs_cbcr_clk;
0332 
0333     /* Enable the Q6SS AHB master CBC, Q6SSTOP_Q6SS_AHBM_CBCR clock */
0334     ret = clk_prepare_enable(wcss->qdsp6ss_abhm_cbcr);
0335     if (ret)
0336         goto disable_tcm_slave_cbcr_clk;
0337 
0338     /* Enable the Q6SS AXI master CBC, Q6SSTOP_Q6SS_AXIM_CBCR clock */
0339     ret = clk_prepare_enable(wcss->qdsp6ss_axim_cbcr);
0340     if (ret)
0341         goto disable_abhm_cbcr_clk;
0342 
0343     /* Enable the Q6SS XO CBC */
0344     val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0345     val |= BIT(0);
0346     writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0347     /* Read CLKOFF bit to go low indicating CLK is enabled */
0348     ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
0349                  val, !(val & BIT(31)), 1,
0350                  HALT_CHECK_MAX_LOOPS);
0351     if (ret) {
0352         dev_err(wcss->dev,
0353             "xo cbcr enabling timed out (rc:%d)\n", ret);
0354         return ret;
0355     }
0356 
0357     writel(0, wcss->reg_base + Q6SS_CGC_OVERRIDE);
0358 
0359     /* Enable QDSP6 sleep clock clock */
0360     val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
0361     val |= BIT(0);
0362     writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
0363 
0364     /* Enable the Enable the Q6 AXI clock, GCC_WDSP_Q6SS_AXIM_CBCR*/
0365     ret = clk_prepare_enable(wcss->gcc_axim_cbcr);
0366     if (ret)
0367         goto disable_sleep_cbcr_clk;
0368 
0369     /* Assert resets, stop core */
0370     val = readl(wcss->reg_base + Q6SS_RESET_REG);
0371     val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
0372     writel(val, wcss->reg_base + Q6SS_RESET_REG);
0373 
0374     /* Program the QDSP6SS PWR_CTL register */
0375     writel(0x01700000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0376 
0377     writel(0x03700000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0378 
0379     writel(0x03300000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0380 
0381     writel(0x033C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0382 
0383     /*
0384      * Enable memories by turning on the QDSP6 memory foot/head switch, one
0385      * bank at a time to avoid in-rush current
0386      */
0387     for (idx = 28; idx >= 0; idx--) {
0388         writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) |
0389             (1 << idx)), wcss->reg_base + Q6SS_MEM_PWR_CTL);
0390     }
0391 
0392     writel(0x031C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0393     writel(0x030C0000, wcss->reg_base + Q6SS_PWR_CTL_REG);
0394 
0395     val = readl(wcss->reg_base + Q6SS_RESET_REG);
0396     val &= ~Q6SS_CORE_ARES;
0397     writel(val, wcss->reg_base + Q6SS_RESET_REG);
0398 
0399     /* Enable the Q6 core clock at the GFM, Q6SSTOP_QDSP6SS_GFMUX_CTL */
0400     val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0401     val |= Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC;
0402     writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0403 
0404     /* Enable sleep clock branch needed for BCR circuit */
0405     ret = clk_prepare_enable(wcss->lcc_bcr_sleep);
0406     if (ret)
0407         goto disable_core_gfmux_clk;
0408 
0409     return 0;
0410 
0411 disable_core_gfmux_clk:
0412     val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0413     val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
0414     writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0415     clk_disable_unprepare(wcss->gcc_axim_cbcr);
0416 disable_sleep_cbcr_clk:
0417     val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
0418     val &= ~Q6SS_CLK_ENABLE;
0419     writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
0420     val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0421     val &= ~Q6SS_CLK_ENABLE;
0422     writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0423     clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr);
0424 disable_abhm_cbcr_clk:
0425     clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr);
0426 disable_tcm_slave_cbcr_clk:
0427     clk_disable_unprepare(wcss->tcm_slave_cbcr);
0428 disable_ahbs_cbcr_clk:
0429     clk_disable_unprepare(wcss->ahbs_cbcr);
0430 disable_csr_cbcr_clk:
0431     clk_disable_unprepare(wcss->lcc_csr_cbcr);
0432 disable_ahbfabric_cbcr_clk:
0433     clk_disable_unprepare(wcss->ahbfabric_cbcr_clk);
0434 disable_gcc_abhs_cbcr_clk:
0435     clk_disable_unprepare(wcss->gcc_abhs_cbcr);
0436 
0437     return ret;
0438 }
0439 
0440 static inline int q6v5_wcss_qcs404_reset(struct q6v5_wcss *wcss)
0441 {
0442     unsigned long val;
0443 
0444     writel(0x80800000, wcss->reg_base + Q6SS_STRAP_ACC);
0445 
0446     /* Start core execution */
0447     val = readl(wcss->reg_base + Q6SS_RESET_REG);
0448     val &= ~Q6SS_STOP_CORE;
0449     writel(val, wcss->reg_base + Q6SS_RESET_REG);
0450 
0451     return 0;
0452 }
0453 
0454 static int q6v5_qcs404_wcss_start(struct rproc *rproc)
0455 {
0456     struct q6v5_wcss *wcss = rproc->priv;
0457     int ret;
0458 
0459     ret = clk_prepare_enable(wcss->xo);
0460     if (ret)
0461         return ret;
0462 
0463     ret = regulator_enable(wcss->cx_supply);
0464     if (ret)
0465         goto disable_xo_clk;
0466 
0467     qcom_q6v5_prepare(&wcss->q6v5);
0468 
0469     ret = q6v5_wcss_qcs404_power_on(wcss);
0470     if (ret) {
0471         dev_err(wcss->dev, "wcss clk_enable failed\n");
0472         goto disable_cx_supply;
0473     }
0474 
0475     writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);
0476 
0477     q6v5_wcss_qcs404_reset(wcss);
0478 
0479     ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
0480     if (ret == -ETIMEDOUT) {
0481         dev_err(wcss->dev, "start timed out\n");
0482         goto disable_cx_supply;
0483     }
0484 
0485     return 0;
0486 
0487 disable_cx_supply:
0488     regulator_disable(wcss->cx_supply);
0489 disable_xo_clk:
0490     clk_disable_unprepare(wcss->xo);
0491 
0492     return ret;
0493 }
0494 
0495 static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
0496                     struct regmap *halt_map,
0497                     u32 offset)
0498 {
0499     unsigned long timeout;
0500     unsigned int val;
0501     int ret;
0502 
0503     /* Check if we're already idle */
0504     ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
0505     if (!ret && val)
0506         return;
0507 
0508     /* Assert halt request */
0509     regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
0510 
0511     /* Wait for halt */
0512     timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
0513     for (;;) {
0514         ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
0515         if (ret || val || time_after(jiffies, timeout))
0516             break;
0517 
0518         msleep(1);
0519     }
0520 
0521     ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
0522     if (ret || !val)
0523         dev_err(wcss->dev, "port failed halt\n");
0524 
0525     /* Clear halt request (port will remain halted until reset) */
0526     regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
0527 }
0528 
0529 static int q6v5_qcs404_wcss_shutdown(struct q6v5_wcss *wcss)
0530 {
0531     unsigned long val;
0532     int ret;
0533 
0534     q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
0535 
0536     /* assert clamps to avoid MX current inrush */
0537     val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0538     val |= (Q6SS_CLAMP_IO | Q6SS_CLAMP_WL | Q6SS_CLAMP_QMC_MEM);
0539     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0540 
0541     /* Disable memories by turning off memory foot/headswitch */
0542     writel((readl(wcss->reg_base + Q6SS_MEM_PWR_CTL) &
0543         ~QDSS_Q6_MEMORIES),
0544         wcss->reg_base + Q6SS_MEM_PWR_CTL);
0545 
0546     /* Clear the BHS_ON bit */
0547     val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0548     val &= ~Q6SS_BHS_ON;
0549     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0550 
0551     clk_disable_unprepare(wcss->ahbfabric_cbcr_clk);
0552     clk_disable_unprepare(wcss->lcc_csr_cbcr);
0553     clk_disable_unprepare(wcss->tcm_slave_cbcr);
0554     clk_disable_unprepare(wcss->qdsp6ss_abhm_cbcr);
0555     clk_disable_unprepare(wcss->qdsp6ss_axim_cbcr);
0556 
0557     val = readl(wcss->reg_base + Q6SS_SLEEP_CBCR);
0558     val &= ~BIT(0);
0559     writel(val, wcss->reg_base + Q6SS_SLEEP_CBCR);
0560 
0561     val = readl(wcss->reg_base + Q6SS_XO_CBCR);
0562     val &= ~BIT(0);
0563     writel(val, wcss->reg_base + Q6SS_XO_CBCR);
0564 
0565     clk_disable_unprepare(wcss->ahbs_cbcr);
0566     clk_disable_unprepare(wcss->lcc_bcr_sleep);
0567 
0568     val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0569     val &= ~(Q6SS_CLK_ENABLE | Q6SS_SWITCH_CLK_SRC);
0570     writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0571 
0572     clk_disable_unprepare(wcss->gcc_abhs_cbcr);
0573 
0574     ret = reset_control_assert(wcss->wcss_reset);
0575     if (ret) {
0576         dev_err(wcss->dev, "wcss_reset failed\n");
0577         return ret;
0578     }
0579     usleep_range(200, 300);
0580 
0581     ret = reset_control_deassert(wcss->wcss_reset);
0582     if (ret) {
0583         dev_err(wcss->dev, "wcss_reset failed\n");
0584         return ret;
0585     }
0586     usleep_range(200, 300);
0587 
0588     clk_disable_unprepare(wcss->gcc_axim_cbcr);
0589 
0590     return 0;
0591 }
0592 
0593 static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
0594 {
0595     int ret;
0596     u32 val;
0597 
0598     /* 1 - Assert WCSS/Q6 HALTREQ */
0599     q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);
0600 
0601     /* 2 - Enable WCSSAON_CONFIG */
0602     val = readl(wcss->rmb_base + SSCAON_CONFIG);
0603     val |= SSCAON_ENABLE;
0604     writel(val, wcss->rmb_base + SSCAON_CONFIG);
0605 
0606     /* 3 - Set SSCAON_CONFIG */
0607     val |= SSCAON_BUS_EN;
0608     val &= ~SSCAON_BUS_MUX_MASK;
0609     writel(val, wcss->rmb_base + SSCAON_CONFIG);
0610 
0611     /* 4 - SSCAON_CONFIG 1 */
0612     val |= BIT(1);
0613     writel(val, wcss->rmb_base + SSCAON_CONFIG);
0614 
0615     /* 5 - wait for SSCAON_STATUS */
0616     ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
0617                  val, (val & 0xffff) == 0x400, 1000,
0618                  HALT_CHECK_MAX_LOOPS);
0619     if (ret) {
0620         dev_err(wcss->dev,
0621             "can't get SSCAON_STATUS rc:%d)\n", ret);
0622         return ret;
0623     }
0624 
0625     /* 6 - De-assert WCSS_AON reset */
0626     reset_control_assert(wcss->wcss_aon_reset);
0627 
0628     /* 7 - Disable WCSSAON_CONFIG 13 */
0629     val = readl(wcss->rmb_base + SSCAON_CONFIG);
0630     val &= ~SSCAON_ENABLE;
0631     writel(val, wcss->rmb_base + SSCAON_CONFIG);
0632 
0633     /* 8 - De-assert WCSS/Q6 HALTREQ */
0634     reset_control_assert(wcss->wcss_reset);
0635 
0636     return 0;
0637 }
0638 
0639 static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
0640 {
0641     int ret;
0642     u32 val;
0643     int i;
0644 
0645     /* 1 - Halt Q6 bus interface */
0646     q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6);
0647 
0648     /* 2 - Disable Q6 Core clock */
0649     val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0650     val &= ~Q6SS_CLK_ENABLE;
0651     writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);
0652 
0653     /* 3 - Clamp I/O */
0654     val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0655     val |= Q6SS_CLAMP_IO;
0656     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0657 
0658     /* 4 - Clamp WL */
0659     val |= QDSS_BHS_ON;
0660     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0661 
0662     /* 5 - Clear Erase standby */
0663     val &= ~Q6SS_L2DATA_STBY_N;
0664     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0665 
0666     /* 6 - Clear Sleep RTN */
0667     val &= ~Q6SS_SLP_RET_N;
0668     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0669 
0670     /* 7 - turn off Q6 memory foot/head switch one bank at a time */
0671     for (i = 0; i < 20; i++) {
0672         val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
0673         val &= ~BIT(i);
0674         writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
0675         mdelay(1);
0676     }
0677 
0678     /* 8 - Assert QMC memory RTN */
0679     val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
0680     val |= Q6SS_CLAMP_QMC_MEM;
0681     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0682 
0683     /* 9 - Turn off BHS */
0684     val &= ~Q6SS_BHS_ON;
0685     writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
0686     udelay(1);
0687 
0688     /* 10 - Wait till BHS Reset is done */
0689     ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
0690                  val, !(val & BHS_EN_REST_ACK), 1000,
0691                  HALT_CHECK_MAX_LOOPS);
0692     if (ret) {
0693         dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
0694         return ret;
0695     }
0696 
0697     /* 11 -  Assert WCSS reset */
0698     reset_control_assert(wcss->wcss_reset);
0699 
0700     /* 12 - Assert Q6 reset */
0701     reset_control_assert(wcss->wcss_q6_reset);
0702 
0703     return 0;
0704 }
0705 
0706 static int q6v5_wcss_stop(struct rproc *rproc)
0707 {
0708     struct q6v5_wcss *wcss = rproc->priv;
0709     int ret;
0710 
0711     /* WCSS powerdown */
0712     if (wcss->requires_force_stop) {
0713         ret = qcom_q6v5_request_stop(&wcss->q6v5, NULL);
0714         if (ret == -ETIMEDOUT) {
0715             dev_err(wcss->dev, "timed out on wait\n");
0716             return ret;
0717         }
0718     }
0719 
0720     if (wcss->version == WCSS_QCS404) {
0721         ret = q6v5_qcs404_wcss_shutdown(wcss);
0722         if (ret)
0723             return ret;
0724     } else {
0725         ret = q6v5_wcss_powerdown(wcss);
0726         if (ret)
0727             return ret;
0728 
0729         /* Q6 Power down */
0730         ret = q6v5_q6_powerdown(wcss);
0731         if (ret)
0732             return ret;
0733     }
0734 
0735     qcom_q6v5_unprepare(&wcss->q6v5);
0736 
0737     return 0;
0738 }
0739 
0740 static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
0741 {
0742     struct q6v5_wcss *wcss = rproc->priv;
0743     int offset;
0744 
0745     offset = da - wcss->mem_reloc;
0746     if (offset < 0 || offset + len > wcss->mem_size)
0747         return NULL;
0748 
0749     return wcss->mem_region + offset;
0750 }
0751 
0752 static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
0753 {
0754     struct q6v5_wcss *wcss = rproc->priv;
0755     int ret;
0756 
0757     ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
0758                     0, wcss->mem_region, wcss->mem_phys,
0759                     wcss->mem_size, &wcss->mem_reloc);
0760     if (ret)
0761         return ret;
0762 
0763     qcom_pil_info_store("wcnss", wcss->mem_phys, wcss->mem_size);
0764 
0765     return ret;
0766 }
0767 
0768 static const struct rproc_ops q6v5_wcss_ipq8074_ops = {
0769     .start = q6v5_wcss_start,
0770     .stop = q6v5_wcss_stop,
0771     .da_to_va = q6v5_wcss_da_to_va,
0772     .load = q6v5_wcss_load,
0773     .get_boot_addr = rproc_elf_get_boot_addr,
0774 };
0775 
0776 static const struct rproc_ops q6v5_wcss_qcs404_ops = {
0777     .start = q6v5_qcs404_wcss_start,
0778     .stop = q6v5_wcss_stop,
0779     .da_to_va = q6v5_wcss_da_to_va,
0780     .load = q6v5_wcss_load,
0781     .get_boot_addr = rproc_elf_get_boot_addr,
0782     .parse_fw = qcom_register_dump_segments,
0783 };
0784 
0785 static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss,
0786                 const struct wcss_data *desc)
0787 {
0788     struct device *dev = wcss->dev;
0789 
0790     if (desc->aon_reset_required) {
0791         wcss->wcss_aon_reset = devm_reset_control_get_exclusive(dev, "wcss_aon_reset");
0792         if (IS_ERR(wcss->wcss_aon_reset)) {
0793             dev_err(wcss->dev, "fail to acquire wcss_aon_reset\n");
0794             return PTR_ERR(wcss->wcss_aon_reset);
0795         }
0796     }
0797 
0798     wcss->wcss_reset = devm_reset_control_get_exclusive(dev, "wcss_reset");
0799     if (IS_ERR(wcss->wcss_reset)) {
0800         dev_err(wcss->dev, "unable to acquire wcss_reset\n");
0801         return PTR_ERR(wcss->wcss_reset);
0802     }
0803 
0804     if (desc->wcss_q6_reset_required) {
0805         wcss->wcss_q6_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_reset");
0806         if (IS_ERR(wcss->wcss_q6_reset)) {
0807             dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
0808             return PTR_ERR(wcss->wcss_q6_reset);
0809         }
0810     }
0811 
0812     wcss->wcss_q6_bcr_reset = devm_reset_control_get_exclusive(dev, "wcss_q6_bcr_reset");
0813     if (IS_ERR(wcss->wcss_q6_bcr_reset)) {
0814         dev_err(wcss->dev, "unable to acquire wcss_q6_bcr_reset\n");
0815         return PTR_ERR(wcss->wcss_q6_bcr_reset);
0816     }
0817 
0818     return 0;
0819 }
0820 
0821 static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
0822                    struct platform_device *pdev)
0823 {
0824     unsigned int halt_reg[MAX_HALT_REG] = {0};
0825     struct device_node *syscon;
0826     struct resource *res;
0827     int ret;
0828 
0829     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
0830     wcss->reg_base = devm_ioremap(&pdev->dev, res->start,
0831                       resource_size(res));
0832     if (!wcss->reg_base)
0833         return -ENOMEM;
0834 
0835     if (wcss->version == WCSS_IPQ8074) {
0836         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
0837         wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
0838         if (IS_ERR(wcss->rmb_base))
0839             return PTR_ERR(wcss->rmb_base);
0840     }
0841 
0842     syscon = of_parse_phandle(pdev->dev.of_node,
0843                   "qcom,halt-regs", 0);
0844     if (!syscon) {
0845         dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
0846         return -EINVAL;
0847     }
0848 
0849     wcss->halt_map = syscon_node_to_regmap(syscon);
0850     of_node_put(syscon);
0851     if (IS_ERR(wcss->halt_map))
0852         return PTR_ERR(wcss->halt_map);
0853 
0854     ret = of_property_read_variable_u32_array(pdev->dev.of_node,
0855                           "qcom,halt-regs",
0856                           halt_reg, 0,
0857                           MAX_HALT_REG);
0858     if (ret < 0) {
0859         dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
0860         return -EINVAL;
0861     }
0862 
0863     wcss->halt_q6 = halt_reg[0];
0864     wcss->halt_wcss = halt_reg[1];
0865     wcss->halt_nc = halt_reg[2];
0866 
0867     return 0;
0868 }
0869 
0870 static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
0871 {
0872     struct reserved_mem *rmem = NULL;
0873     struct device_node *node;
0874     struct device *dev = wcss->dev;
0875 
0876     node = of_parse_phandle(dev->of_node, "memory-region", 0);
0877     if (node)
0878         rmem = of_reserved_mem_lookup(node);
0879     of_node_put(node);
0880 
0881     if (!rmem) {
0882         dev_err(dev, "unable to acquire memory-region\n");
0883         return -EINVAL;
0884     }
0885 
0886     wcss->mem_phys = rmem->base;
0887     wcss->mem_reloc = rmem->base;
0888     wcss->mem_size = rmem->size;
0889     wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
0890     if (!wcss->mem_region) {
0891         dev_err(dev, "unable to map memory region: %pa+%pa\n",
0892             &rmem->base, &rmem->size);
0893         return -EBUSY;
0894     }
0895 
0896     return 0;
0897 }
0898 
0899 static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss)
0900 {
0901     int ret;
0902 
0903     wcss->xo = devm_clk_get(wcss->dev, "xo");
0904     if (IS_ERR(wcss->xo)) {
0905         ret = PTR_ERR(wcss->xo);
0906         if (ret != -EPROBE_DEFER)
0907             dev_err(wcss->dev, "failed to get xo clock");
0908         return ret;
0909     }
0910 
0911     wcss->gcc_abhs_cbcr = devm_clk_get(wcss->dev, "gcc_abhs_cbcr");
0912     if (IS_ERR(wcss->gcc_abhs_cbcr)) {
0913         ret = PTR_ERR(wcss->gcc_abhs_cbcr);
0914         if (ret != -EPROBE_DEFER)
0915             dev_err(wcss->dev, "failed to get gcc abhs clock");
0916         return ret;
0917     }
0918 
0919     wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr");
0920     if (IS_ERR(wcss->gcc_axim_cbcr)) {
0921         ret = PTR_ERR(wcss->gcc_axim_cbcr);
0922         if (ret != -EPROBE_DEFER)
0923             dev_err(wcss->dev, "failed to get gcc axim clock\n");
0924         return ret;
0925     }
0926 
0927     wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev,
0928                         "lcc_ahbfabric_cbc");
0929     if (IS_ERR(wcss->ahbfabric_cbcr_clk)) {
0930         ret = PTR_ERR(wcss->ahbfabric_cbcr_clk);
0931         if (ret != -EPROBE_DEFER)
0932             dev_err(wcss->dev, "failed to get ahbfabric clock\n");
0933         return ret;
0934     }
0935 
0936     wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc");
0937     if (IS_ERR(wcss->lcc_csr_cbcr)) {
0938         ret = PTR_ERR(wcss->lcc_csr_cbcr);
0939         if (ret != -EPROBE_DEFER)
0940             dev_err(wcss->dev, "failed to get csr cbcr clk\n");
0941         return ret;
0942     }
0943 
0944     wcss->ahbs_cbcr = devm_clk_get(wcss->dev,
0945                        "lcc_abhs_cbc");
0946     if (IS_ERR(wcss->ahbs_cbcr)) {
0947         ret = PTR_ERR(wcss->ahbs_cbcr);
0948         if (ret != -EPROBE_DEFER)
0949             dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n");
0950         return ret;
0951     }
0952 
0953     wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev,
0954                         "lcc_tcm_slave_cbc");
0955     if (IS_ERR(wcss->tcm_slave_cbcr)) {
0956         ret = PTR_ERR(wcss->tcm_slave_cbcr);
0957         if (ret != -EPROBE_DEFER)
0958             dev_err(wcss->dev, "failed to get tcm cbcr clk\n");
0959         return ret;
0960     }
0961 
0962     wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc");
0963     if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) {
0964         ret = PTR_ERR(wcss->qdsp6ss_abhm_cbcr);
0965         if (ret != -EPROBE_DEFER)
0966             dev_err(wcss->dev, "failed to get abhm cbcr clk\n");
0967         return ret;
0968     }
0969 
0970     wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc");
0971     if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) {
0972         ret = PTR_ERR(wcss->qdsp6ss_axim_cbcr);
0973         if (ret != -EPROBE_DEFER)
0974             dev_err(wcss->dev, "failed to get axim cbcr clk\n");
0975         return ret;
0976     }
0977 
0978     wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep");
0979     if (IS_ERR(wcss->lcc_bcr_sleep)) {
0980         ret = PTR_ERR(wcss->lcc_bcr_sleep);
0981         if (ret != -EPROBE_DEFER)
0982             dev_err(wcss->dev, "failed to get bcr cbcr clk\n");
0983         return ret;
0984     }
0985 
0986     return 0;
0987 }
0988 
0989 static int q6v5_wcss_init_regulator(struct q6v5_wcss *wcss)
0990 {
0991     wcss->cx_supply = devm_regulator_get(wcss->dev, "cx");
0992     if (IS_ERR(wcss->cx_supply))
0993         return PTR_ERR(wcss->cx_supply);
0994 
0995     regulator_set_load(wcss->cx_supply, 100000);
0996 
0997     return 0;
0998 }
0999 
1000 static int q6v5_wcss_probe(struct platform_device *pdev)
1001 {
1002     const struct wcss_data *desc;
1003     struct q6v5_wcss *wcss;
1004     struct rproc *rproc;
1005     int ret;
1006 
1007     desc = device_get_match_data(&pdev->dev);
1008     if (!desc)
1009         return -EINVAL;
1010 
1011     rproc = rproc_alloc(&pdev->dev, pdev->name, desc->ops,
1012                 desc->firmware_name, sizeof(*wcss));
1013     if (!rproc) {
1014         dev_err(&pdev->dev, "failed to allocate rproc\n");
1015         return -ENOMEM;
1016     }
1017 
1018     wcss = rproc->priv;
1019     wcss->dev = &pdev->dev;
1020     wcss->version = desc->version;
1021 
1022     wcss->version = desc->version;
1023     wcss->requires_force_stop = desc->requires_force_stop;
1024 
1025     ret = q6v5_wcss_init_mmio(wcss, pdev);
1026     if (ret)
1027         goto free_rproc;
1028 
1029     ret = q6v5_alloc_memory_region(wcss);
1030     if (ret)
1031         goto free_rproc;
1032 
1033     if (wcss->version == WCSS_QCS404) {
1034         ret = q6v5_wcss_init_clock(wcss);
1035         if (ret)
1036             goto free_rproc;
1037 
1038         ret = q6v5_wcss_init_regulator(wcss);
1039         if (ret)
1040             goto free_rproc;
1041     }
1042 
1043     ret = q6v5_wcss_init_reset(wcss, desc);
1044     if (ret)
1045         goto free_rproc;
1046 
1047     ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, desc->crash_reason_smem, NULL, NULL);
1048     if (ret)
1049         goto free_rproc;
1050 
1051     qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
1052     qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
1053 
1054     if (desc->ssctl_id)
1055         wcss->sysmon = qcom_add_sysmon_subdev(rproc,
1056                               desc->sysmon_name,
1057                               desc->ssctl_id);
1058 
1059     ret = rproc_add(rproc);
1060     if (ret)
1061         goto free_rproc;
1062 
1063     platform_set_drvdata(pdev, rproc);
1064 
1065     return 0;
1066 
1067 free_rproc:
1068     rproc_free(rproc);
1069 
1070     return ret;
1071 }
1072 
1073 static int q6v5_wcss_remove(struct platform_device *pdev)
1074 {
1075     struct rproc *rproc = platform_get_drvdata(pdev);
1076     struct q6v5_wcss *wcss = rproc->priv;
1077 
1078     qcom_q6v5_deinit(&wcss->q6v5);
1079     rproc_del(rproc);
1080     rproc_free(rproc);
1081 
1082     return 0;
1083 }
1084 
1085 static const struct wcss_data wcss_ipq8074_res_init = {
1086     .firmware_name = "IPQ8074/q6_fw.mdt",
1087     .crash_reason_smem = WCSS_CRASH_REASON,
1088     .aon_reset_required = true,
1089     .wcss_q6_reset_required = true,
1090     .ops = &q6v5_wcss_ipq8074_ops,
1091     .requires_force_stop = true,
1092 };
1093 
1094 static const struct wcss_data wcss_qcs404_res_init = {
1095     .crash_reason_smem = WCSS_CRASH_REASON,
1096     .firmware_name = "wcnss.mdt",
1097     .version = WCSS_QCS404,
1098     .aon_reset_required = false,
1099     .wcss_q6_reset_required = false,
1100     .ssr_name = "mpss",
1101     .sysmon_name = "wcnss",
1102     .ssctl_id = 0x12,
1103     .ops = &q6v5_wcss_qcs404_ops,
1104     .requires_force_stop = false,
1105 };
1106 
1107 static const struct of_device_id q6v5_wcss_of_match[] = {
1108     { .compatible = "qcom,ipq8074-wcss-pil", .data = &wcss_ipq8074_res_init },
1109     { .compatible = "qcom,qcs404-wcss-pil", .data = &wcss_qcs404_res_init },
1110     { },
1111 };
1112 MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
1113 
1114 static struct platform_driver q6v5_wcss_driver = {
1115     .probe = q6v5_wcss_probe,
1116     .remove = q6v5_wcss_remove,
1117     .driver = {
1118         .name = "qcom-q6v5-wcss-pil",
1119         .of_match_table = q6v5_wcss_of_match,
1120     },
1121 };
1122 module_platform_driver(q6v5_wcss_driver);
1123 
1124 MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
1125 MODULE_LICENSE("GPL v2");