Adding OpenWrt support for Xiaomi AX3600 (Part 1)

Yeah I had to manually apply the patch but I never get that event. I don't know if it's due to me moving the address in DTS. or maybe something else missing from q6v5_wcss but i l also see no qmi events.

The qcom_q6v5_wcss.c i have made

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2016-2018 Linaro Ltd.
 * Copyright (C) 2014 Sony Mobile Communications AB
 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
 */
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/soc/qcom/mdt_loader.h>
#include <linux/qcom_scm.h>
#include "qcom_common.h"
#include "qcom_q6v5.h"

#define WCSS_CRASH_REASON		421

/* Q6SS Register Offsets */
#define Q6SS_RESET_REG		0x014
#define Q6SS_GFMUX_CTL_REG		0x020
#define Q6SS_PWR_CTL_REG		0x030
#define Q6SS_MEM_PWR_CTL		0x0B0

/* AXI Halt Register Offsets */
#define AXI_HALTREQ_REG			0x0
#define AXI_HALTACK_REG			0x4
#define AXI_IDLE_REG			0x8

#define HALT_ACK_TIMEOUT_MS		100

/* Q6SS_RESET */
#define Q6SS_STOP_CORE			BIT(0)
#define Q6SS_CORE_ARES			BIT(1)
#define Q6SS_BUS_ARES_ENABLE		BIT(2)

/* Q6SS_GFMUX_CTL */
#define Q6SS_CLK_ENABLE			BIT(1)

/* Q6SS_PWR_CTL */
#define Q6SS_L2DATA_STBY_N		BIT(18)
#define Q6SS_SLP_RET_N			BIT(19)
#define Q6SS_CLAMP_IO			BIT(20)
#define QDSS_BHS_ON			BIT(21)

/* Q6SS parameters */
#define Q6SS_LDO_BYP		BIT(25)
#define Q6SS_BHS_ON		BIT(24)
#define Q6SS_CLAMP_WL		BIT(21)
#define Q6SS_CLAMP_QMC_MEM		BIT(22)
#define HALT_CHECK_MAX_LOOPS		200
#define Q6SS_XO_CBCR		GENMASK(5, 3)

/* Q6SS config/status registers */
#define TCSR_GLOBAL_CFG0	0x0
#define TCSR_GLOBAL_CFG1	0x4
#define SSCAON_CONFIG		0x8
#define SSCAON_STATUS		0xc
#define Q6SS_BHS_STATUS		0x78
#define Q6SS_RST_EVB		0x10

#define BHS_EN_REST_ACK		BIT(0)
#define SSCAON_ENABLE		BIT(13)
#define SSCAON_BUS_EN		BIT(15)
#define SSCAON_BUS_MUX_MASK	GENMASK(18, 16)

#define MEM_BANKS		19
#define TCSR_WCSS_CLK_MASK	0x1F
#define TCSR_WCSS_CLK_ENABLE	0x14

#define WCNSS_PAS_ID		6

struct q6v5_wcss {
	struct device *dev;

	void __iomem *reg_base;
	void __iomem *rmb_base;

	struct regmap *halt_map;
	u32 halt_q6;
	u32 halt_wcss;
	u32 halt_nc;

	struct reset_control *wcss_aon_reset;
	struct reset_control *wcss_reset;
	struct reset_control *wcss_q6_reset;

	struct qcom_q6v5 q6v5;

	phys_addr_t mem_phys;
	phys_addr_t mem_reloc;
	void *mem_region;
	size_t mem_size;
	
	struct qcom_rproc_glink glink_subdev;
	struct qcom_rproc_ssr ssr_subdev;
	
	bool need_mem_protection;
	const char *m3_firmware_name;

	struct clk *prng_clk;
};

static int q6v5_wcss_reset(struct q6v5_wcss *wcss)
{
	int ret;
	u32 val;
	int i;

	/* Assert resets, stop core */
	val = readl(wcss->reg_base + Q6SS_RESET_REG);
	val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE;
	writel(val, wcss->reg_base + Q6SS_RESET_REG);

	/* BHS require xo cbcr to be enabled */
	val = readl(wcss->reg_base + Q6SS_XO_CBCR);
	val |= 0x1;
	writel(val, wcss->reg_base + Q6SS_XO_CBCR);

	/* Read CLKOFF bit to go low indicating CLK is enabled */
	ret = readl_poll_timeout(wcss->reg_base + Q6SS_XO_CBCR,
				 val, !(val & BIT(31)), 1,
				 HALT_CHECK_MAX_LOOPS);
	if (ret) {
		dev_err(wcss->dev,
			"xo cbcr enabling timed out (rc:%d)\n", ret);
		return ret;
	}
	/* Enable power block headswitch and wait for it to stabilize */
	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
	val |= Q6SS_BHS_ON;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
	udelay(1);

	/* Put LDO in bypass mode */
	val |= Q6SS_LDO_BYP;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* Deassert Q6 compiler memory clamp */
	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
	val &= ~Q6SS_CLAMP_QMC_MEM;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* Deassert memory peripheral sleep and L2 memory standby */
	val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* Turn on L1, L2, ETB and JU memories 1 at a time */
	val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
	for (i = MEM_BANKS; i >= 0; i--) {
		val |= BIT(i);
		writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
		/*
		 * Read back value to ensure the write is done then
		 * wait for 1us for both memory peripheral and data
		 * array to turn on.
		 */
		val |= readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
		udelay(1);
	}
	/* Remove word line clamp */
	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
	val &= ~Q6SS_CLAMP_WL;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* Remove IO clamp */
	val &= ~Q6SS_CLAMP_IO;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* Bring core out of reset */
	val = readl(wcss->reg_base + Q6SS_RESET_REG);
	val &= ~Q6SS_CORE_ARES;
	writel(val, wcss->reg_base + Q6SS_RESET_REG);

	/* Turn on core clock */
	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
	val |= Q6SS_CLK_ENABLE;
	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);

	/* Start core execution */
	val = readl(wcss->reg_base + Q6SS_RESET_REG);
	val &= ~Q6SS_STOP_CORE;
	writel(val, wcss->reg_base + Q6SS_RESET_REG);

	return 0;
}

static int q6v5_wcss_start(struct rproc *rproc)
{
	struct q6v5_wcss *wcss = rproc->priv;
	int ret;

	ret = clk_prepare_enable(wcss->prng_clk);
	if (ret) {
		dev_err(wcss->dev, "prng clock enable failed\n");
		return ret;
	}

	qcom_q6v5_prepare(&wcss->q6v5);
	
	if (wcss->need_mem_protection) {
		printk("Q6V5 qcom_scm_pas_auth_and_reset\n");
		ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
		if (ret) {
			dev_err(wcss->dev, "wcss_reset failed\n");
			return ret;
		}
		goto wait_for_reset;
	}

	/* Release Q6 and WCSS reset */
	ret = reset_control_deassert(wcss->wcss_reset);
	if (ret) {
		dev_err(wcss->dev, "wcss_reset failed\n");
		return ret;
	}

	ret = reset_control_deassert(wcss->wcss_q6_reset);
	if (ret) {
		dev_err(wcss->dev, "wcss_q6_reset failed\n");
		goto wcss_reset;
	}

	/* Lithium configuration - clock gating and bus arbitration */
	ret = regmap_update_bits(wcss->halt_map,
				 wcss->halt_nc + TCSR_GLOBAL_CFG0,
				 TCSR_WCSS_CLK_MASK,
				 TCSR_WCSS_CLK_ENABLE);
	if (ret)
		goto wcss_q6_reset;

	ret = regmap_update_bits(wcss->halt_map,
				 wcss->halt_nc + TCSR_GLOBAL_CFG1,
				 1, 0);
	if (ret)
		goto wcss_q6_reset;

	/* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
	writel(rproc->bootaddr >> 4, wcss->reg_base + Q6SS_RST_EVB);

	ret = q6v5_wcss_reset(wcss);
	if (ret)
		goto wcss_q6_reset;

wait_for_reset:
	ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ);
	if (ret == -ETIMEDOUT)
		dev_err(wcss->dev, "start timed out\n");

	return ret;

wcss_q6_reset:
	reset_control_assert(wcss->wcss_q6_reset);

wcss_reset:
	reset_control_assert(wcss->wcss_reset);

	return ret;
}

static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss,
				    struct regmap *halt_map,
				    u32 offset)
{
	unsigned long timeout;
	unsigned int val;
	int ret;

	/* Check if we're already idle */
	ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
	if (!ret && val)
		return;

	/* Assert halt request */
	regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);

	/* Wait for halt */
	timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
	for (;;) {
		ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
		if (ret || val || time_after(jiffies, timeout))
			break;

		msleep(1);
	}

	ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
	if (ret || !val)
		dev_err(wcss->dev, "port failed halt\n");

	/* Clear halt request (port will remain halted until reset) */
	regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
}

static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss)
{
	int ret;
	u32 val;

	/* 1 - Assert WCSS/Q6 HALTREQ */
	q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss);

	/* 2 - Enable WCSSAON_CONFIG */
	val = readl(wcss->rmb_base + SSCAON_CONFIG);
	val |= SSCAON_ENABLE;
	writel(val, wcss->rmb_base + SSCAON_CONFIG);

	/* 3 - Set SSCAON_CONFIG */
	val |= SSCAON_BUS_EN;
	val &= ~SSCAON_BUS_MUX_MASK;
	writel(val, wcss->rmb_base + SSCAON_CONFIG);

	/* 4 - SSCAON_CONFIG 1 */
	val |= BIT(1);
	writel(val, wcss->rmb_base + SSCAON_CONFIG);

	/* 5 - wait for SSCAON_STATUS */
	ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS,
				 val, (val & 0xffff) == 0x400, 1000,
				 HALT_CHECK_MAX_LOOPS);
	if (ret) {
		dev_err(wcss->dev,
			"can't get SSCAON_STATUS rc:%d)\n", ret);
		return ret;
	}

	/* 6 - De-assert WCSS_AON reset */
	reset_control_assert(wcss->wcss_aon_reset);

	/* 7 - Disable WCSSAON_CONFIG 13 */
	val = readl(wcss->rmb_base + SSCAON_CONFIG);
	val &= ~SSCAON_ENABLE;
	writel(val, wcss->rmb_base + SSCAON_CONFIG);

	/* 8 - De-assert WCSS/Q6 HALTREQ */
	reset_control_assert(wcss->wcss_reset);

	return 0;
}

static int q6v5_q6_powerdown(struct q6v5_wcss *wcss)
{
	int ret;
	u32 val;
	int i;

	/* 1 - Halt Q6 bus interface */
	q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6);

	/* 2 - Disable Q6 Core clock */
	val = readl(wcss->reg_base + Q6SS_GFMUX_CTL_REG);
	val &= ~Q6SS_CLK_ENABLE;
	writel(val, wcss->reg_base + Q6SS_GFMUX_CTL_REG);

	/* 3 - Clamp I/O */
	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
	val |= Q6SS_CLAMP_IO;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* 4 - Clamp WL */
	val |= QDSS_BHS_ON;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* 5 - Clear Erase standby */
	val &= ~Q6SS_L2DATA_STBY_N;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* 6 - Clear Sleep RTN */
	val &= ~Q6SS_SLP_RET_N;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* 7 - turn off Q6 memory foot/head switch one bank at a time */
	for (i = 0; i < 20; i++) {
		val = readl(wcss->reg_base + Q6SS_MEM_PWR_CTL);
		val &= ~BIT(i);
		writel(val, wcss->reg_base + Q6SS_MEM_PWR_CTL);
		mdelay(1);
	}

	/* 8 - Assert QMC memory RTN */
	val = readl(wcss->reg_base + Q6SS_PWR_CTL_REG);
	val |= Q6SS_CLAMP_QMC_MEM;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);

	/* 9 - Turn off BHS */
	val &= ~Q6SS_BHS_ON;
	writel(val, wcss->reg_base + Q6SS_PWR_CTL_REG);
	udelay(1);

	/* 10 - Wait till BHS Reset is done */
	ret = readl_poll_timeout(wcss->reg_base + Q6SS_BHS_STATUS,
				 val, !(val & BHS_EN_REST_ACK), 1000,
				 HALT_CHECK_MAX_LOOPS);
	if (ret) {
		dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret);
		return ret;
	}

	/* 11 -  Assert WCSS reset */
	reset_control_assert(wcss->wcss_reset);

	/* 12 - Assert Q6 reset */
	reset_control_assert(wcss->wcss_q6_reset);

	return 0;
}

static int q6v5_wcss_stop(struct rproc *rproc)
{
	struct q6v5_wcss *wcss = rproc->priv;
	int ret;
	
	if (wcss->need_mem_protection) {
		printk("Q6V5 Call qcom_scm_pas_shutdown\n");
		ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
		if (ret) {
			dev_err(wcss->dev, "not able to shutdown\n");
			return ret;
		}
		goto pas_done;
	}
	
	/* WCSS powerdown */
	ret = qcom_q6v5_request_stop(&wcss->q6v5);
	if (ret == -ETIMEDOUT) {
		dev_err(wcss->dev, "timed out on wait\n");
		return ret;
	}

	ret = q6v5_wcss_powerdown(wcss);
	if (ret)
		return ret;

	/* Q6 Power down */
	ret = q6v5_q6_powerdown(wcss);
	if (ret)
		return ret;

pas_done:
	clk_disable_unprepare(wcss->prng_clk);
	qcom_q6v5_unprepare(&wcss->q6v5);

	return 0;
}

static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
{
	struct q6v5_wcss *wcss = rproc->priv;
	int offset;

	offset = da - wcss->mem_reloc;
	if (offset < 0 || offset + len > wcss->mem_size)
		return NULL;

	return wcss->mem_region + offset;
}

static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
{
	struct q6v5_wcss *wcss = rproc->priv;
	const struct firmware *m3_fw;
	int ret;

	ret = request_firmware(&m3_fw, wcss->m3_firmware_name,
				       wcss->dev);
	printk("Q6V5 use request_firmware\n");
	
	if (ret)
		goto skip_m3;

	printk("Q6V5 m3 use qcom_mdt_load_no_init\n");
	ret = qcom_mdt_load_no_init(wcss->dev, m3_fw,
				    wcss->m3_firmware_name, 0,
				    wcss->mem_region, wcss->mem_phys,
				    wcss->mem_size, &wcss->mem_reloc);
	if (ret) {
		dev_err(wcss->dev, "can't load m3_fw.bXX\n");
		return ret;
	}

skip_m3:
	if (wcss->need_mem_protection) {
		printk("Q6V5 use qcom_mdt_load\n");
		return qcom_mdt_load(wcss->dev, fw, rproc->firmware,
				     WCNSS_PAS_ID, wcss->mem_region,
				     wcss->mem_phys, wcss->mem_size,
				     &wcss->mem_reloc);
	}

	printk("Q6V5 use qcom_mdt_load_no_init\n");
	return qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware,
				     0, wcss->mem_region, wcss->mem_phys,
				     wcss->mem_size, &wcss->mem_reloc);
}

static const struct rproc_ops q6v5_wcss_ops = {
	.start = q6v5_wcss_start,
	.stop = q6v5_wcss_stop,
	.da_to_va = q6v5_wcss_da_to_va,
	.load = q6v5_wcss_load,
	.get_boot_addr = rproc_elf_get_boot_addr,
};

static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss)
{
	struct device *dev = wcss->dev;

	wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset");
	if (IS_ERR(wcss->wcss_aon_reset)) {
		dev_err(wcss->dev, "unable to acquire wcss_aon_reset\n");
		return PTR_ERR(wcss->wcss_aon_reset);
	}

	wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset");
	if (IS_ERR(wcss->wcss_reset)) {
		dev_err(wcss->dev, "unable to acquire wcss_reset\n");
		return PTR_ERR(wcss->wcss_reset);
	}

	wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset");
	if (IS_ERR(wcss->wcss_q6_reset)) {
		dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n");
		return PTR_ERR(wcss->wcss_q6_reset);
	}

	return 0;
}

static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss,
			       struct platform_device *pdev)
{
	struct of_phandle_args args;
	struct resource *res;
	int ret;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
	wcss->reg_base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(wcss->reg_base))
		return PTR_ERR(wcss->reg_base);

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
	wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(wcss->rmb_base))
		return PTR_ERR(wcss->rmb_base);

	ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
					       "qcom,halt-regs", 3, 0, &args);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
		return -EINVAL;
	}

	wcss->halt_map = syscon_node_to_regmap(args.np);
	of_node_put(args.np);
	if (IS_ERR(wcss->halt_map))
		return PTR_ERR(wcss->halt_map);

	wcss->halt_q6 = args.args[0];
	wcss->halt_wcss = args.args[1];
	wcss->halt_nc = args.args[2];

	return 0;
}

static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss)
{
	struct reserved_mem *rmem = NULL;
	struct device_node *node;
	struct device *dev = wcss->dev;

	node = of_parse_phandle(dev->of_node, "memory-region", 0);
	if (node)
		rmem = of_reserved_mem_lookup(node);
	of_node_put(node);

	if (!rmem) {
		dev_err(dev, "unable to acquire memory-region\n");
		return -EINVAL;
	}

	wcss->mem_phys = rmem->base;
	wcss->mem_reloc = rmem->base;
	wcss->mem_size = rmem->size;
	wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size);
	if (!wcss->mem_region) {
		dev_err(dev, "unable to map memory region: %pa+%pa\n",
			&rmem->base, &rmem->size);
		return -EBUSY;
	}

	return 0;
}

static int q6v5_wcss_probe(struct platform_device *pdev)
{
	printk("q6v5_wcss_probe ++");

	struct q6v5_wcss *wcss;
	struct rproc *rproc;
	int ret;

	rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ops,
			    "IPQ8074/q6_fw.mdt", sizeof(*wcss));
	if (!rproc) {
		dev_err(&pdev->dev, "failed to allocate rproc\n");
		return -ENOMEM;
	}

	wcss = rproc->priv;
	wcss->dev = &pdev->dev;
	wcss->m3_firmware_name =  "IPQ8074/m3_fw.mdt";
	
	wcss->prng_clk = devm_clk_get(wcss->dev, "prng");
	if (IS_ERR(wcss->prng_clk)) {
		ret = PTR_ERR(wcss->prng_clk);
		if (ret != -EPROBE_DEFER)
			dev_err(wcss->dev, "Failed to get prng clock\n");
		goto free_rproc;
	}

	if (qcom_scm_is_available()) {
		printk("q6v5 qcom_scm_is_available ++\n");
		wcss->need_mem_protection = true;
	}

	ret = q6v5_wcss_init_mmio(wcss, pdev);
	if (ret)
		goto free_rproc;

	ret = q6v5_alloc_memory_region(wcss);
	if (ret)
		goto free_rproc;

	ret = q6v5_wcss_init_reset(wcss);
	if (ret)
		goto free_rproc;

	ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, WCSS_CRASH_REASON, NULL);
	if (ret)
		goto free_rproc;

	qcom_add_glink_subdev(rproc, &wcss->glink_subdev);
	qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");

	ret = rproc_add(rproc);
	if (ret)
		goto free_rproc;

	platform_set_drvdata(pdev, rproc);

	printk("q6v5_wcss_probe --");
	return 0;

free_rproc:
	rproc_free(rproc);

	return ret;
}

static int q6v5_wcss_remove(struct platform_device *pdev)
{
	struct rproc *rproc = platform_get_drvdata(pdev);

	rproc_del(rproc);
	rproc_free(rproc);

	return 0;
}

static const struct of_device_id q6v5_wcss_of_match[] = {
	{ .compatible = "qcom,ipq8074-wcss-pil" },
	{ },
};
MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);

static struct platform_driver q6v5_wcss_driver = {
	.probe = q6v5_wcss_probe,
	.remove = q6v5_wcss_remove,
	.driver = {
		.name = "qcom-q6v5-wcss-pil",
		.of_match_table = q6v5_wcss_of_match,
	},
};
module_platform_driver(q6v5_wcss_driver);

MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader");
MODULE_LICENSE("GPL v2");

Have a look through and see if I have missed anything important to ipq8074

In fact, in qsdk, it just ioremap here, so the mac driver still can use devm_ioremap_resource for reg = <0xc000000 0x2000000>;

So I don't think we should adjust the reg to 0xd000000, 0x2000000.

I have tried to use ioremap but still no phy register.

Im 99% sure the problem is with the q6 init within qcom_q6v5_wcss. Could try pull that in from qsdk ?

Yes, I'm sure the problem is in qcom_q6v5_wcss, but you know, it's very complicated, I'm not sure if a working qcom_q6v5_wcss from qsdk could support the ath11k, right?

Do you have any datasheet for these chips?

Nope, just the kernel source from QSDK.

If you apply my qcom_q6v5_wcss.c file able and also enable

+CONFIG_QRTR=y
+CONFIG_QRTR_SMD=y
+CONFIG_QCOM_APCS_IPC=y

You sould get

[    9.369752] Q6V5 use request_firmware
[    9.377199] Q6V5 use qcom_mdt_load_no_init
[    9.387161] qcom-q6v5-wcss-pil cd00000.q6v5_wcss: q6v5_wcss_start ++
[    9.387192] qcom-q6v5-wcss-pil cd00000.q6v5_wcss: call clk_prepare_enable
[   14.562514] qcom-q6v5-wcss-pil cd00000.q6v5_wcss: start timed out
[   14.562543] remoteproc remoteproc0: can't start rproc cd00000.q6v5_wcss: -110
[   14.567616] ath11k d000000.wifi: failed to boot the remote processor Q6
[   14.574715] ath11k d000000.wifi: failed to power up :-110
[   14.581216] ath11k d000000.wifi: failed to create soc core: -110
[   14.586697] ath11k d000000.wifi: failed to init core: -110
[   14.592864] ath11k: probe of d000000.wifi failed with error -110

Looks like scm is broken on mainline ipq8074 :confused: i guess we are stuck (i cant think of anything other than porting the qca drivers for the FW load and Q6 init)

No these messages.
I think you could push your code.
I'm not sure how many different between my code and yours.

1 Like

Pushed my changes and ath11k FW package

I have ath11k starting, will push my changes tomorrow AM (getting late for me)

[    8.405073] ath11k d000000.wifi: qmi target: chip_id: 0x0, chip_family: 0x0, board_id: 0xff, soc_id: 0xffffffff
[    8.407418] ath11k d000000.wifi: qmi fw_version: 0x210c04a5 fw_build_timestamp: 2020-06-24 04:34 fw_build_id: QC_IMAGE_VERSION_STRING=WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2
[    8.419241] ath11k d000000.wifi: Downloading BDF: IPQ8074/board-2.bin, size: 1049108
[    8.419400] kmodloader: done loading kernel modules from /etc/modules.d/*
[    8.434379] ath11k d000000.wifi: qmi downloading BDF: IPQ8074/caldata.bin, size: 131072
[    8.449862] ath11k d000000.wifi: qmi BDF downloaded

However it does hard reset the device after loading caldata.bin extracted from a QSDK build.

4 Likes

Great job!

All changed pushed to https://github.com/BuzzBumbleBee/openwrt/commits/ax3600

Should get you to the following point without caldata, but I get a crash as soon as the caldata is loaded.....

But Q6 is booted and working as expected and can now talk to ath11k via qmi / glink

[    9.413223] ath11k d000000.wifi: qmi target: chip_id: 0x0, chip_family: 0x0, board_id: 0xff, soc_id: 0xffffffff
[    9.415693] ath11k d000000.wifi: qmi fw_version: 0x210c04a5 fw_build_timestamp: 2020-06-24 04:34 fw_build_id: QC_IMAGE_VERSION_STRING=WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2
[    9.425763] kmodloader: done loading kernel modules from /etc/modules.d/*
[    9.427084] ath11k d000000.wifi: Downloading BDF: IPQ8074/board-2.bin, size: 1049108
[    9.449404] ath11k d000000.wifi: Direct firmware load for IPQ8074/caldata.bin failed with error -2
[    9.455856] ath11k d000000.wifi: Falling back to sysfs fallback for: IPQ8074/caldata.bin
[    9.472548] ath11k d000000.wifi: qmi failed to load CAL: IPQ8074/caldata.bin
[    9.472825] ath11k d000000.wifi: qmi failed to load board data file:-12



BusyBox v1.31.1 () built-in shell (ash)

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 OpenWrt SNAPSHOT, r0+13963-734742d883
 -----------------------------------------------------
=== WARNING! =====================================
There is no root password defined on this device!
Use the "passwd" command to set up a new password
in order to prevent unauthorized SSH logins.
--------------------------------------------------
root@OpenWrt:/# [   19.035537] nss-dp 3a001000.dp1 eth0: nss_dp_edma: Registering netdev eth0(qcom-id:1) with EDMA
[   19.035578] nss-dp 3a001000.dp1 eth0: netif_napi_add() called with weight 100
[   19.045058] br-lan: port 1(eth0) entered blocking state
[   19.050676] br-lan: port 1(eth0) entered disabled state
[   19.055787] device eth0 entered promiscuous mode
[   19.061815] br-lan: port 1(eth0) entered blocking state
[   19.065478] br-lan: port 1(eth0) entered forwarding state
[   19.075924] nss-dp 3a001200.dp2 eth1: nss_dp_edma: Registering netdev eth1(qcom-id:2) with EDMA
[   20.066631] IPv6: ADDRCONF(NETDEV_CHANGE): br-lan: link becomes ready

1 Like

How to extract the caldata from mtd?

This is the stock script

#!/bin/sh
#
# Copyright (c) 2015 The Linux Foundation. All rights reserved.
# Copyright (C) 2011 OpenWrt.org

. /lib/ipq806x.sh

do_load_ipq4019_board_bin()
{
    local board=$(ipq806x_board_name)
    local mtdblock=$(find_mtd_part 0:ART)

    local apdk="/tmp"

    HK_BD_FILENAME=/lib/firmware/IPQ8074/bdwlan.bin

    if [ -z "$mtdblock" ]; then
        # read from mmc
        mtdblock=$(find_mmc_part 0:ART)
    fi

    [ -n "$mtdblock" ] || return

    # load board.bin
    case "$board" in
            ap-dk0*)
                    mkdir -p ${apdk}
                    dd if=${mtdblock} of=${apdk}/wifi0.caldata bs=32 count=377 skip=128
                    dd if=${mtdblock} of=${apdk}/wifi1.caldata bs=32 count=377 skip=640
            ;;
            ap16* | ap148*)
                    mkdir -p ${apdk}
                    dd if=${mtdblock} of=${apdk}/wifi0.caldata bs=32 count=377 skip=128
                    dd if=${mtdblock} of=${apdk}/wifi1.caldata bs=32 count=377 skip=640
                    dd if=${mtdblock} of=${apdk}/wifi2.caldata bs=32 count=377 skip=1152
            ;;
            ap-hk01-*)
                    mkdir -p ${apdk}/IPQ8074
                    if [ -f "$HK_BD_FILENAME" ]; then
                        FILESIZE=$(stat -Lc%s "$HK_BD_FILENAME")
                    else
                        FILESIZE=131072
                    fi
                    dd if=${mtdblock} of=${apdk}/IPQ8074/caldata.bin bs=1 count=$FILESIZE skip=4096
                    [ -L /lib/firmware/IPQ8074/caldata.bin ] || \
                    ln -s ${apdk}/IPQ8074/caldata.bin /lib/firmware/IPQ8074/caldata.bin
            ;;
            ap-hk* | ap-ac* | ap-oa*)
                    mkdir -p ${apdk}/IPQ8074
                    dd if=${mtdblock} of=${apdk}/wifi1.caldata bs=1 count=2116 skip=208896
                    if [ -f "$HK_BD_FILENAME" ]; then
                        FILESIZE=$(stat -Lc%s "$HK_BD_FILENAME")
                    else
                        FILESIZE=131072
                    fi
                    dd if=${mtdblock} of=${apdk}/IPQ8074/caldata.bin bs=1 count=$FILESIZE skip=4096
                    [ -L /lib/firmware/IPQ8074/caldata.bin ] || \
                    ln -s ${apdk}/IPQ8074/caldata.bin /lib/firmware/IPQ8074/caldata.bin
            ;;
   esac
}

Id get an MTD backup of ART 1st tho

Just wanted to say a massive thank you to @Apache14 , @gmzhuo , @efsg et al. for all of their hard work. It's looking really good, very much appreciated.

3 Likes
9.424317] ath11k d000000.wifi: qmi target: chip_id: 0x0, chip_family: 0x0, board_id: 0xff, soc_id: 0xffffffff

These chip id, socid looks strange.

And i'm still curious why we should use the address 0xd000000.

I have patched the wcss so you can try the lower region. Feel free to try move it back. I wont have chance to test that until after work.

He He He

With 0xc000000 I got

root@(none):/lib/modules/5.4.52# iw phy0 info
Wiphy phy0
        max # scan SSIDs: 16
        max scan IEs length: 142 bytes
        max # sched scan SSIDs: 0
        max # match sets: 0
        max # scan plans: 1
        max scan plan interval: -1
        max scan plan iterations: 0
        Retry short limit: 7
        Retry long limit: 4
        Coverage class: 0 (up to 0m)
        Device supports AP-side u-APSD.
        Available Antennas: TX 0xf0 RX 0xf0
        Configured Antennas: TX 0xf0 RX 0xf0
        Supported interface modes:
                 * managed
                 * AP
                 * AP/VLAN
                 * monitor
                 * mesh point
        Band 2:
                Capabilities: 0x19ef
                        RX LDPC
                        HT20/HT40
                        SM Power Save disabled
                        RX HT20 SGI
                        RX HT40 SGI
                        TX STBC
                        RX STBC 1-stream
                        Max AMSDU length: 7935 bytes
                        DSSS/CCK HT40
                Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
                Minimum RX AMPDU time spacing: No restriction (0x00)
                HT TX/RX MCS rate indexes supported: 0-31
                VHT Capabilities (0x738bf9b2):
                        Max MPDU length: 11454
                        Supported Channel Width: neither 160 nor 80+80
                        RX LDPC
                        short GI (80 MHz)
                        TX STBC
                        SU Beamformer
                        SU Beamformee
                        MU Beamformer
                        RX antenna pattern consistency
                        TX antenna pattern consistency
                VHT RX MCS set:
                        1 streams: MCS 0-9
                        2 streams: MCS 0-9
                        3 streams: MCS 0-9
                        4 streams: MCS 0-9
                        5 streams: not supported
                        6 streams: not supported
                        7 streams: not supported
                        8 streams: not supported
                VHT RX highest supported: 0 Mbps
                VHT TX MCS set:
                        1 streams: MCS 0-9
                        2 streams: MCS 0-9
                        3 streams: MCS 0-9
                        4 streams: MCS 0-9
                        5 streams: not supported
                        6 streams: not supported
                        7 streams: not supported
                        8 streams: not supported
                VHT TX highest supported: 0 Mbps
                Frequencies:
                        * 5180 MHz [36] (30.0 dBm)
                        * 5200 MHz [40] (30.0 dBm)
                        * 5220 MHz [44] (30.0 dBm)
                        * 5240 MHz [48] (30.0 dBm)
                        * 5260 MHz [52] (24.0 dBm) (radar detection)
                        * 5280 MHz [56] (24.0 dBm) (radar detection)
                        * 5300 MHz [60] (24.0 dBm) (radar detection)
                        * 5320 MHz [64] (24.0 dBm) (radar detection)
                        * 5500 MHz [100] (24.0 dBm) (radar detection)
                        * 5520 MHz [104] (24.0 dBm) (radar detection)
                        * 5540 MHz [108] (24.0 dBm) (radar detection)
                        * 5560 MHz [112] (24.0 dBm) (radar detection)
                        * 5580 MHz [116] (24.0 dBm) (radar detection)
                        * 5600 MHz [120] (24.0 dBm) (radar detection)
                        * 5620 MHz [124] (24.0 dBm) (radar detection)
                        * 5640 MHz [128] (24.0 dBm) (radar detection)
                        * 5660 MHz [132] (24.0 dBm) (radar detection)
                        * 5680 MHz [136] (24.0 dBm) (radar detection)
                        * 5700 MHz [140] (24.0 dBm) (radar detection)
                        * 5720 MHz [144] (24.0 dBm) (radar detection)
                        * 5745 MHz [149] (30.0 dBm)
                        * 5765 MHz [153] (30.0 dBm)
                        * 5785 MHz [157] (30.0 dBm)
                        * 5805 MHz [161] (30.0 dBm)
                        * 5825 MHz [165] (30.0 dBm)
                        * 5845 MHz [169] (disabled)
                        * 5865 MHz [173] (disabled)
        valid interface combinations:
                 * #{ managed } <= 1, #{ AP, mesh point } <= 16,
                   total <= 16, #channels <= 1, STA/AP BI must match, radar detect widths: { 20 MHz (no HT), 20 MHz, 40 MHz, 80 MHz }

        HT Capability overrides:
                 * MCS: ff ff ff ff ff ff ff ff ff ff
                 * maximum A-MSDU length
                 * supported channel width
                 * short GI for 40 MHz
                 * max A-MPDU length exponent
                 * min MPDU start spacing
        Supported extended features:
                * [ RRM ]: RRM
                * [ CQM_RSSI_LIST ]: multiple CQM_RSSI_THOLD records
                * [ CONTROL_PORT_OVER_NL80211 ]: control port over nl80211
                * [ STA_TX_PWR ]: TX power control per station
3 Likes

Boom !

Fantastic, ill update my branch with that address at lunch :smile:

Cant seem to scan on 2g or 5g but startup / init seems fine for me.

iw list

root@OpenWrt:/# iw list
Wiphy phy1
        max # scan SSIDs: 16
        max scan IEs length: 152 bytes
        max # sched scan SSIDs: 0
        max # match sets: 0
        max # scan plans: 1
        max scan plan interval: -1
        max scan plan iterations: 0
        Retry short limit: 7
        Retry long limit: 4
        Coverage class: 0 (up to 0m)
        Device supports AP-side u-APSD.
        Available Antennas: TX 0x3 RX 0x3
        Configured Antennas: TX 0x3 RX 0x3
        Supported interface modes:
                 * managed
                 * AP
                 * AP/VLAN
                 * monitor
                 * mesh point
        Band 1:
                Capabilities: 0x11e7
                        RX LDPC
                        HT20/HT40
                        Dynamic SM Power Save
                        RX HT20 SGI
                        RX HT40 SGI
                        TX STBC
                        RX STBC 1-stream
                        Max AMSDU length: 3839 bytes
                        DSSS/CCK HT40
                Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
                Minimum RX AMPDU time spacing: No restriction (0x00)
                HT TX/RX MCS rate indexes supported: 0-15
                Frequencies:
                        * 2412 MHz [1] (30.0 dBm)
                        * 2417 MHz [2] (30.0 dBm)
                        * 2422 MHz [3] (30.0 dBm)
                        * 2427 MHz [4] (30.0 dBm)
                        * 2432 MHz [5] (30.0 dBm)
                        * 2437 MHz [6] (30.0 dBm)
                        * 2442 MHz [7] (30.0 dBm)
                        * 2447 MHz [8] (30.0 dBm)
                        * 2452 MHz [9] (30.0 dBm)
                        * 2457 MHz [10] (30.0 dBm)
                        * 2462 MHz [11] (30.0 dBm)
                        * 2467 MHz [12] (disabled)
                        * 2472 MHz [13] (disabled)
                        * 2484 MHz [14] (disabled)
        valid interface combinations:
                 * #{ managed } <= 1, #{ AP, mesh point } <= 16,
                   total <= 16, #channels <= 1, STA/AP BI must match, radar detect widths: { 20 MHz (no HT), 20 MHz, 40 MHz, 80 MHz }

        HT Capability overrides:
                 * MCS: ff ff ff ff ff ff ff ff ff ff
                 * maximum A-MSDU length
                 * supported channel width
                 * short GI for 40 MHz
                 * max A-MPDU length exponent
                 * min MPDU start spacing
        Supported extended features:
                * [ RRM ]: RRM
                * [ CQM_RSSI_LIST ]: multiple CQM_RSSI_THOLD records
                * [ CONTROL_PORT_OVER_NL80211 ]: control port over nl80211
                * [ STA_TX_PWR ]: TX power control per station
Wiphy phy0
        max # scan SSIDs: 16
        max scan IEs length: 142 bytes
        max # sched scan SSIDs: 0
        max # match sets: 0
        max # scan plans: 1
        max scan plan interval: -1
        max scan plan iterations: 0
        Retry short limit: 7
        Retry long limit: 4
        Coverage class: 0 (up to 0m)
        Device supports AP-side u-APSD.
        Available Antennas: TX 0xf0 RX 0xf0
        Configured Antennas: TX 0xf0 RX 0xf0
        Supported interface modes:
                 * managed
                 * AP
                 * AP/VLAN
                 * monitor
                 * mesh point
        Band 2:
                Capabilities: 0x19e7
                        RX LDPC
                        HT20/HT40
                        Dynamic SM Power Save
                        RX HT20 SGI
                        RX HT40 SGI
                        TX STBC
                        RX STBC 1-stream
                        Max AMSDU length: 7935 bytes
                        DSSS/CCK HT40
                Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
                Minimum RX AMPDU time spacing: No restriction (0x00)
                HT TX/RX MCS rate indexes supported: 0-31
                VHT Capabilities (0x738bf9b2):
                        Max MPDU length: 11454
                        Supported Channel Width: neither 160 nor 80+80
                        RX LDPC
                        short GI (80 MHz)
                        TX STBC
                        SU Beamformer
                        SU Beamformee
                        MU Beamformer
                        RX antenna pattern consistency
                        TX antenna pattern consistency
                VHT RX MCS set:
                        1 streams: MCS 0-9
                        2 streams: MCS 0-9
                        3 streams: MCS 0-9
                        4 streams: MCS 0-9
                        5 streams: not supported
                        6 streams: not supported
                        7 streams: not supported
                        8 streams: not supported
                VHT RX highest supported: 0 Mbps
                VHT TX MCS set:
                        1 streams: MCS 0-9
                        2 streams: MCS 0-9
                        3 streams: MCS 0-9
                        4 streams: MCS 0-9
                        5 streams: not supported
                        6 streams: not supported
                        7 streams: not supported
                        8 streams: not supported                                                      +-----------------------------+
                VHT TX highest supported: 0 Mbps                                                      |                             |
                Frequencies:                                                                          |  Cannot open /dev/ttyUSB0!  |
                        * 5180 MHz [36] (30.0 dBm)                                                    |                             |
                        * 5200 MHz [40] (30.0 dBm)                                                    +-----------------------------+
                        * 5220 MHz [44] (30.0 dBm)
                        * 5240 MHz [48] (30.0 dBm)
                        * 5260 MHz [52] (24.0 dBm) (radar detection)
                        * 5280 MHz [56] (24.0 dBm) (radar detection)
                        * 5300 MHz [60] (24.0 dBm) (radar detection)
                        * 5320 MHz [64] (24.0 dBm) (radar detection)
                        * 5500 MHz [100] (24.0 dBm) (radar detection)
                        * 5520 MHz [104] (24.0 dBm) (radar detection)
                        * 5540 MHz [108] (24.0 dBm) (radar detection)
                        * 5560 MHz [112] (24.0 dBm) (radar detection)
                        * 5580 MHz [116] (24.0 dBm) (radar detection)
                        * 5600 MHz [120] (24.0 dBm) (radar detection)
                        * 5620 MHz [124] (24.0 dBm) (radar detection)
                        * 5640 MHz [128] (24.0 dBm) (radar detection)
                        * 5660 MHz [132] (24.0 dBm) (radar detection)
                        * 5680 MHz [136] (24.0 dBm) (radar detection)
                        * 5700 MHz [140] (24.0 dBm) (radar detection)
                        * 5720 MHz [144] (24.0 dBm) (radar detection)
                        * 5745 MHz [149] (30.0 dBm)
                        * 5765 MHz [153] (30.0 dBm)
                        * 5785 MHz [157] (30.0 dBm)
                        * 5805 MHz [161] (30.0 dBm)
                        * 5825 MHz [165] (30.0 dBm)
                        * 5845 MHz [169] (disabled)
                        * 5865 MHz [173] (disabled)
        valid interface combinations:
                 * #{ managed } <= 1, #{ AP, mesh point } <= 16,
                   total <= 16, #channels <= 1, STA/AP BI must match, radar detect widths: { 20 MHz (no HT), 20 MHz, 40 MHz, 80 MHz }

        HT Capability overrides:
                 * MCS: ff ff ff ff ff ff ff ff ff ff
                 * maximum A-MSDU length
                 * supported channel width
                 * short GI for 40 MHz
                 * max A-MPDU length exponent
                 * min MPDU start spacing
        Supported extended features:
                * [ RRM ]: RRM
                * [ CQM_RSSI_LIST ]: multiple CQM_RSSI_THOLD records
                * [ CONTROL_PORT_OVER_NL80211 ]: control port over nl80211
                * [ STA_TX_PWR ]: TX power control per station

iw reg get

root@OpenWrt:/# iw reg get
global
country 00: DFS-UNSET
        (2402 - 2472 @ 40), (N/A, 20), (N/A)
        (2457 - 2482 @ 20), (N/A, 20), (N/A), AUTO-BW, PASSIVE-SCAN
        (2474 - 2494 @ 20), (N/A, 20), (N/A), NO-OFDM, PASSIVE-SCAN
        (5170 - 5250 @ 80), (N/A, 20), (N/A), AUTO-BW
        (5250 - 5330 @ 80), (N/A, 20), (0 ms), DFS, AUTO-BW, PASSIVE-SCAN
        (5490 - 5730 @ 160), (N/A, 20), (0 ms), DFS, PASSIVE-SCAN
        (5735 - 5835 @ 80), (N/A, 20), (N/A), PASSIVE-SCAN
        (57240 - 63720 @ 2160), (N/A, 0), (N/A)

phy#1 (self-managed)
country US: DFS-FCC
        (2402 - 2472 @ 40), (6, 30), (N/A)
        (5170 - 5250 @ 80), (6, 30), (N/A), AUTO-BW
        (5250 - 5330 @ 80), (6, 24), (0 ms), DFS, AUTO-BW
        (5490 - 5730 @ 160), (6, 24), (0 ms), DFS, AUTO-BW
        (5735 - 5835 @ 80), (6, 30), (N/A), AUTO-BW

phy#0 (self-managed)
country US: DFS-FCC
        (2402 - 2472 @ 40), (6, 30), (N/A)
        (5170 - 5250 @ 80), (6, 30), (N/A), AUTO-BW
        (5250 - 5330 @ 80), (6, 24), (0 ms), DFS, AUTO-BW
        (5490 - 5730 @ 160), (6, 24), (0 ms), DFS, AUTO-BW
        (5735 - 5835 @ 80), (6, 30), (N/A), AUTO-BW