Unverified Commit 35a53670 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'mtk-soc-for-v6.20' of...

Merge tag 'mtk-soc-for-v6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux into soc/drivers

MediaTek soc driver updates

This adds:
 - A socinfo entry for the MT8371 Genio 520 SoC
 - Support for the Dynamic Voltage and Frequency Scaling
   Resource Controller (DVFSRC) version 4, found in the
   new MediaTek Kompanio Ultra (MT8196) SoC
 - Initial support for the CMDQ mailbox found in the MT8196.
 - A memory leak fix in the MediaTek SVS driver's debug ops.

* tag 'mtk-soc-for-v6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux

:
  soc: mediatek: mtk-cmdq: Add mminfra_offset adjustment for DRAM addresses
  soc: mediatek: mtk-cmdq: Extend cmdq_pkt_write API for SoCs without subsys ID
  soc: mediatek: mtk-cmdq: Add pa_base parsing for hardware without subsys ID support
  soc: mediatek: mtk-cmdq: Add cmdq_get_mbox_priv() in cmdq_pkt_create()
  mailbox: mtk-cmdq: Add driver data to support for MT8196
  mailbox: mtk-cmdq: Add mminfra_offset configuration for DRAM transaction
  mailbox: mtk-cmdq: Add GCE hardware virtualization configuration
  mailbox: mtk-cmdq: Add cmdq private data to cmdq_pkt for generating instruction
  soc: mediatek: mtk-dvfsrc: Rework bandwidth calculations
  soc: mediatek: mtk-dvfsrc: Get and Enable DVFSRC clock
  soc: mediatek: mtk-dvfsrc: Add support for DVFSRCv4 and MT8196
  soc: mediatek: mtk-dvfsrc: Write bandwidth to EMI DDR if present
  soc: mediatek: mtk-dvfsrc: Add a new callback for calc_dram_bw
  soc: mediatek: mtk-dvfsrc: Add and propagate DVFSRC bandwidth type
  soc: mediatek: mtk-dvfsrc: Change error check for DVFSRCv4 START cmd
  dt-bindings: soc: mediatek: dvfsrc: Document clock
  soc: mediatek: mtk-socinfo: Add entry for MT8371AV/AZA Genio 520
  soc: mediatek: svs: Fix memory leak in svs_enable_debug_write()

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents b04d336f 22ce09ce
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -34,6 +34,10 @@ properties:
    maxItems: 1
    description: DVFSRC common register address and length.

  clocks:
    items:
      - description: Clock that drives the DVFSRC MCU

  regulators:
    type: object
    $ref: /schemas/regulator/mediatek,mt6873-dvfsrc-regulator.yaml#
@@ -50,6 +54,7 @@ additionalProperties: false

examples:
  - |
    #include <dt-bindings/clock/mt8195-clk.h>
    soc {
        #address-cells = <2>;
        #size-cells = <2>;
@@ -57,6 +62,7 @@ examples:
        system-controller@10012000 {
            compatible = "mediatek,mt8195-dvfsrc";
            reg = <0 0x10012000 0 0x1000>;
            clocks = <&topckgen CLK_TOP_DVFSRC>;

            regulators {
                compatible = "mediatek,mt8195-dvfsrc-regulator";
+72 −2
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sizes.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox/mtk-cmdq-mailbox.h>
#include <linux/of.h>
@@ -43,6 +44,13 @@
#define GCE_CTRL_BY_SW				GENMASK(2, 0)
#define GCE_DDR_EN				GENMASK(18, 16)

#define GCE_VM_ID_MAP(n)		(0x5018 + (n) / 10 * 4)
#define GCE_VM_ID_MAP_THR_FLD_SHIFT(n)		((n) % 10 * 3)
#define GCE_VM_ID_MAP_HOST_VM			GENMASK(2, 0)
#define GCE_VM_CPR_GSIZE		0x50c4
#define GCE_VM_CPR_GSIZE_FLD_SHIFT(vm_id)	((vm_id) * 4)
#define GCE_VM_CPR_GSIZE_MAX			GENMASK(3, 0)

#define CMDQ_THR_ACTIVE_SLOT_CYCLES	0x3200
#define CMDQ_THR_ENABLED		0x1
#define CMDQ_THR_DISABLED		0x0
@@ -87,22 +95,33 @@ struct cmdq {
struct gce_plat {
	u32 thread_nr;
	u8 shift;
	dma_addr_t mminfra_offset;
	bool control_by_sw;
	bool sw_ddr_en;
	bool gce_vm;
	u32 gce_num;
};

static inline u32 cmdq_convert_gce_addr(dma_addr_t addr, const struct gce_plat *pdata)
{
	/* Convert DMA addr (PA or IOVA) to GCE readable addr */
	return addr >> pdata->shift;
	return (addr + pdata->mminfra_offset) >> pdata->shift;
}

static inline dma_addr_t cmdq_revert_gce_addr(u32 addr, const struct gce_plat *pdata)
{
	/* Revert GCE readable addr to DMA addr (PA or IOVA) */
	return (dma_addr_t)addr << pdata->shift;
	return ((dma_addr_t)addr << pdata->shift) - pdata->mminfra_offset;
}

void cmdq_get_mbox_priv(struct mbox_chan *chan, struct cmdq_mbox_priv *priv)
{
	struct cmdq *cmdq = container_of(chan->mbox, struct cmdq, mbox);

	priv->shift_pa = cmdq->pdata->shift;
	priv->mminfra_offset = cmdq->pdata->mminfra_offset;
}
EXPORT_SYMBOL(cmdq_get_mbox_priv);

u8 cmdq_get_shift_pa(struct mbox_chan *chan)
{
@@ -112,6 +131,45 @@ u8 cmdq_get_shift_pa(struct mbox_chan *chan)
}
EXPORT_SYMBOL(cmdq_get_shift_pa);

static void cmdq_vm_init(struct cmdq *cmdq)
{
	int i;
	u32 vm_cpr_gsize = 0, vm_id_map = 0;
	u32 *vm_map = NULL;

	if (!cmdq->pdata->gce_vm)
		return;

	vm_map = kcalloc(cmdq->pdata->thread_nr, sizeof(*vm_map), GFP_KERNEL);
	if (!vm_map)
		return;

	/* only configure the max CPR SRAM size to host vm (vm_id = 0) currently */
	vm_cpr_gsize = GCE_VM_CPR_GSIZE_MAX << GCE_VM_CPR_GSIZE_FLD_SHIFT(0);

	/* set all thread mapping to host vm currently */
	for (i = 0; i < cmdq->pdata->thread_nr; i++)
		vm_map[i] = GCE_VM_ID_MAP_HOST_VM << GCE_VM_ID_MAP_THR_FLD_SHIFT(i);

	/* set the amount of CPR SRAM to allocate to each VM */
	writel(vm_cpr_gsize, cmdq->base + GCE_VM_CPR_GSIZE);

	/* config CPR_GSIZE before setting VM_ID_MAP to avoid data leakage */
	for (i = 0; i < cmdq->pdata->thread_nr; i++) {
		vm_id_map |= vm_map[i];
		/* config every 10 threads, e.g., thread id=0~9, 10~19, ..., into one register */
		if ((i + 1) % 10 == 0) {
			writel(vm_id_map, cmdq->base + GCE_VM_ID_MAP(i));
			vm_id_map = 0;
		}
	}
	/* config remaining threads settings */
	if (cmdq->pdata->thread_nr % 10 != 0)
		writel(vm_id_map, cmdq->base + GCE_VM_ID_MAP(cmdq->pdata->thread_nr - 1));

	kfree(vm_map);
}

static void cmdq_gctl_value_toggle(struct cmdq *cmdq, bool ddr_enable)
{
	u32 val = cmdq->pdata->control_by_sw ? GCE_CTRL_BY_SW : 0;
@@ -156,6 +214,7 @@ static void cmdq_init(struct cmdq *cmdq)

	WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks));

	cmdq_vm_init(cmdq);
	cmdq_gctl_value_toggle(cmdq, true);

	writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
@@ -782,6 +841,16 @@ static const struct gce_plat gce_plat_mt8195 = {
	.gce_num = 2
};

static const struct gce_plat gce_plat_mt8196 = {
	.thread_nr = 32,
	.shift = 3,
	.mminfra_offset = SZ_2G,
	.control_by_sw = true,
	.sw_ddr_en = true,
	.gce_vm = true,
	.gce_num = 2
};

static const struct of_device_id cmdq_of_ids[] = {
	{.compatible = "mediatek,mt6779-gce", .data = (void *)&gce_plat_mt6779},
	{.compatible = "mediatek,mt8173-gce", .data = (void *)&gce_plat_mt8173},
@@ -790,6 +859,7 @@ static const struct of_device_id cmdq_of_ids[] = {
	{.compatible = "mediatek,mt8188-gce", .data = (void *)&gce_plat_mt8188},
	{.compatible = "mediatek,mt8192-gce", .data = (void *)&gce_plat_mt8192},
	{.compatible = "mediatek,mt8195-gce", .data = (void *)&gce_plat_mt8195},
	{.compatible = "mediatek,mt8196-gce", .data = (void *)&gce_plat_mt8196},
	{}
};
MODULE_DEVICE_TABLE(of, cmdq_of_ids);
+73 −4
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/mailbox_controller.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/soc/mediatek/mtk-cmdq.h>

#define CMDQ_WRITE_ENABLE_MASK	BIT(0)
@@ -60,20 +61,41 @@ int cmdq_dev_get_client_reg(struct device *dev,
			    struct cmdq_client_reg *client_reg, int idx)
{
	struct of_phandle_args spec;
	struct resource res;
	int err;

	if (!client_reg)
		return -ENOENT;

	err = of_address_to_resource(dev->of_node, 0, &res);
	if (err) {
		dev_err(dev, "Missing reg in %s node\n", dev->of_node->full_name);
		return -EINVAL;
	}
	client_reg->pa_base = res.start;

	err = of_parse_phandle_with_fixed_args(dev->of_node,
					       "mediatek,gce-client-reg",
					       3, idx, &spec);
	if (err < 0) {
		dev_warn(dev,
		dev_dbg(dev,
			"error %d can't parse gce-client-reg property (%d)",
			err, idx);

		return err;
		/* make subsys invalid */
		client_reg->subsys = CMDQ_SUBSYS_INVALID;

		/*
		 * All GCEs support writing register PA with mask without subsys,
		 * but this requires extra GCE instructions to convert the PA into
		 * a format that GCE can handle, which is less performance than
		 * directly using subsys. Therefore, when subsys is available,
		 * we prefer to use subsys for writing register PA.
		 */
		client_reg->pkt_write = cmdq_pkt_write_pa;
		client_reg->pkt_write_mask = cmdq_pkt_write_mask_pa;

		return 0;
	}

	client_reg->subsys = (u8)spec.args[0];
@@ -81,6 +103,9 @@ int cmdq_dev_get_client_reg(struct device *dev,
	client_reg->size = (u16)spec.args[2];
	of_node_put(spec.np);

	client_reg->pkt_write = cmdq_pkt_write_subsys;
	client_reg->pkt_write_mask = cmdq_pkt_write_mask_subsys;

	return 0;
}
EXPORT_SYMBOL(cmdq_dev_get_client_reg);
@@ -140,6 +165,7 @@ int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t siz
	}

	pkt->pa_base = dma_addr;
	cmdq_get_mbox_priv(client->chan, &pkt->priv);

	return 0;
}
@@ -201,6 +227,26 @@ int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
}
EXPORT_SYMBOL(cmdq_pkt_write);

int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
		      u16 offset, u32 value)
{
	int err;

	err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
	if (err < 0)
		return err;

	return cmdq_pkt_write_s_value(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_LOW(offset), value);
}
EXPORT_SYMBOL(cmdq_pkt_write_pa);

int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
			  u16 offset, u32 value)
{
	return cmdq_pkt_write(pkt, subsys, offset, value);
}
EXPORT_SYMBOL(cmdq_pkt_write_subsys);

int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
			u16 offset, u32 value, u32 mask)
{
@@ -218,6 +264,27 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
}
EXPORT_SYMBOL(cmdq_pkt_write_mask);

int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
			   u16 offset, u32 value, u32 mask)
{
	int err;

	err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
	if (err < 0)
		return err;

	return cmdq_pkt_write_s_mask_value(pkt, CMDQ_THR_SPR_IDX0,
					   CMDQ_ADDR_LOW(offset), value, mask);
}
EXPORT_SYMBOL(cmdq_pkt_write_mask_pa);

int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
			       u16 offset, u32 value, u32 mask)
{
	return cmdq_pkt_write_mask(pkt, subsys, offset, value, mask);
}
EXPORT_SYMBOL(cmdq_pkt_write_mask_subsys);

int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
		    u16 reg_idx)
{
@@ -305,6 +372,7 @@ int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_
	int ret;

	/* read the value of src_addr into high_addr_reg_idx */
	src_addr += pkt->priv.mminfra_offset;
	ret = cmdq_pkt_assign(pkt, high_addr_reg_idx, CMDQ_ADDR_HIGH(src_addr));
	if (ret < 0)
		return ret;
@@ -313,6 +381,7 @@ int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_
		return ret;

	/* write the value of value_reg_idx into dst_addr */
	dst_addr += pkt->priv.mminfra_offset;
	ret = cmdq_pkt_assign(pkt, high_addr_reg_idx, CMDQ_ADDR_HIGH(dst_addr));
	if (ret < 0)
		return ret;
@@ -438,7 +507,7 @@ int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mas
	inst.op = CMDQ_CODE_MASK;
	inst.dst_t = CMDQ_REG_TYPE;
	inst.sop = CMDQ_POLL_ADDR_GPR;
	inst.value = addr;
	inst.value = addr + pkt->priv.mminfra_offset;
	ret = cmdq_pkt_append_command(pkt, inst);
	if (ret < 0)
		return ret;
@@ -498,7 +567,7 @@ int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa)
	struct cmdq_instruction inst = {
		.op = CMDQ_CODE_JUMP,
		.offset = CMDQ_JUMP_ABSOLUTE,
		.value = addr >> shift_pa
		.value = (addr +  pkt->priv.mminfra_offset) >> pkt->priv.shift_pa
	};
	return cmdq_pkt_append_command(pkt, inst);
}
+332 −32

File changed.

Preview size limit exceeded, changes collapsed.

+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ static struct socinfo_data socinfo_data_table[] = {
	MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380", 0x81950400, CELL_NOT_USED),
	MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380", 0x81950404, CELL_NOT_USED),
	MTK_SOCINFO_ENTRY("MT8370", "MT8370AV/AZA", "Genio 510", 0x83700000, 0x00000081),
	MTK_SOCINFO_ENTRY("MT8371", "MT8371AV/AZA", "Genio 520", 0x83710000, 0x00000081),
	MTK_SOCINFO_ENTRY("MT8390", "MT8390AV/AZA", "Genio 700", 0x83900000, 0x00000080),
	MTK_SOCINFO_ENTRY("MT8391", "MT8391AV/AZA", "Genio 720", 0x83910000, 0x00000080),
	MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950100, CELL_NOT_USED),
Loading