Skip to content

Commit 35a5367

Browse files
committed
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: Arnd Bergmann <arnd@arndb.de>
2 parents b04d336 + 22ce09c commit 35a5367

8 files changed

Lines changed: 598 additions & 41 deletions

File tree

Documentation/devicetree/bindings/soc/mediatek/mediatek,mt8183-dvfsrc.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ properties:
3434
maxItems: 1
3535
description: DVFSRC common register address and length.
3636

37+
clocks:
38+
items:
39+
- description: Clock that drives the DVFSRC MCU
40+
3741
regulators:
3842
type: object
3943
$ref: /schemas/regulator/mediatek,mt6873-dvfsrc-regulator.yaml#
@@ -50,13 +54,15 @@ additionalProperties: false
5054

5155
examples:
5256
- |
57+
#include <dt-bindings/clock/mt8195-clk.h>
5358
soc {
5459
#address-cells = <2>;
5560
#size-cells = <2>;
5661
5762
system-controller@10012000 {
5863
compatible = "mediatek,mt8195-dvfsrc";
5964
reg = <0 0x10012000 0 0x1000>;
65+
clocks = <&topckgen CLK_TOP_DVFSRC>;
6066
6167
regulators {
6268
compatible = "mediatek,mt8195-dvfsrc-regulator";

drivers/mailbox/mtk-cmdq-mailbox.c

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/module.h>
1515
#include <linux/platform_device.h>
1616
#include <linux/pm_runtime.h>
17+
#include <linux/sizes.h>
1718
#include <linux/mailbox_controller.h>
1819
#include <linux/mailbox/mtk-cmdq-mailbox.h>
1920
#include <linux/of.h>
@@ -43,6 +44,13 @@
4344
#define GCE_CTRL_BY_SW GENMASK(2, 0)
4445
#define GCE_DDR_EN GENMASK(18, 16)
4546

47+
#define GCE_VM_ID_MAP(n) (0x5018 + (n) / 10 * 4)
48+
#define GCE_VM_ID_MAP_THR_FLD_SHIFT(n) ((n) % 10 * 3)
49+
#define GCE_VM_ID_MAP_HOST_VM GENMASK(2, 0)
50+
#define GCE_VM_CPR_GSIZE 0x50c4
51+
#define GCE_VM_CPR_GSIZE_FLD_SHIFT(vm_id) ((vm_id) * 4)
52+
#define GCE_VM_CPR_GSIZE_MAX GENMASK(3, 0)
53+
4654
#define CMDQ_THR_ACTIVE_SLOT_CYCLES 0x3200
4755
#define CMDQ_THR_ENABLED 0x1
4856
#define CMDQ_THR_DISABLED 0x0
@@ -87,22 +95,33 @@ struct cmdq {
8795
struct gce_plat {
8896
u32 thread_nr;
8997
u8 shift;
98+
dma_addr_t mminfra_offset;
9099
bool control_by_sw;
91100
bool sw_ddr_en;
101+
bool gce_vm;
92102
u32 gce_num;
93103
};
94104

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

101111
static inline dma_addr_t cmdq_revert_gce_addr(u32 addr, const struct gce_plat *pdata)
102112
{
103113
/* Revert GCE readable addr to DMA addr (PA or IOVA) */
104-
return (dma_addr_t)addr << pdata->shift;
114+
return ((dma_addr_t)addr << pdata->shift) - pdata->mminfra_offset;
115+
}
116+
117+
void cmdq_get_mbox_priv(struct mbox_chan *chan, struct cmdq_mbox_priv *priv)
118+
{
119+
struct cmdq *cmdq = container_of(chan->mbox, struct cmdq, mbox);
120+
121+
priv->shift_pa = cmdq->pdata->shift;
122+
priv->mminfra_offset = cmdq->pdata->mminfra_offset;
105123
}
124+
EXPORT_SYMBOL(cmdq_get_mbox_priv);
106125

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

134+
static void cmdq_vm_init(struct cmdq *cmdq)
135+
{
136+
int i;
137+
u32 vm_cpr_gsize = 0, vm_id_map = 0;
138+
u32 *vm_map = NULL;
139+
140+
if (!cmdq->pdata->gce_vm)
141+
return;
142+
143+
vm_map = kcalloc(cmdq->pdata->thread_nr, sizeof(*vm_map), GFP_KERNEL);
144+
if (!vm_map)
145+
return;
146+
147+
/* only configure the max CPR SRAM size to host vm (vm_id = 0) currently */
148+
vm_cpr_gsize = GCE_VM_CPR_GSIZE_MAX << GCE_VM_CPR_GSIZE_FLD_SHIFT(0);
149+
150+
/* set all thread mapping to host vm currently */
151+
for (i = 0; i < cmdq->pdata->thread_nr; i++)
152+
vm_map[i] = GCE_VM_ID_MAP_HOST_VM << GCE_VM_ID_MAP_THR_FLD_SHIFT(i);
153+
154+
/* set the amount of CPR SRAM to allocate to each VM */
155+
writel(vm_cpr_gsize, cmdq->base + GCE_VM_CPR_GSIZE);
156+
157+
/* config CPR_GSIZE before setting VM_ID_MAP to avoid data leakage */
158+
for (i = 0; i < cmdq->pdata->thread_nr; i++) {
159+
vm_id_map |= vm_map[i];
160+
/* config every 10 threads, e.g., thread id=0~9, 10~19, ..., into one register */
161+
if ((i + 1) % 10 == 0) {
162+
writel(vm_id_map, cmdq->base + GCE_VM_ID_MAP(i));
163+
vm_id_map = 0;
164+
}
165+
}
166+
/* config remaining threads settings */
167+
if (cmdq->pdata->thread_nr % 10 != 0)
168+
writel(vm_id_map, cmdq->base + GCE_VM_ID_MAP(cmdq->pdata->thread_nr - 1));
169+
170+
kfree(vm_map);
171+
}
172+
115173
static void cmdq_gctl_value_toggle(struct cmdq *cmdq, bool ddr_enable)
116174
{
117175
u32 val = cmdq->pdata->control_by_sw ? GCE_CTRL_BY_SW : 0;
@@ -156,6 +214,7 @@ static void cmdq_init(struct cmdq *cmdq)
156214

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

217+
cmdq_vm_init(cmdq);
159218
cmdq_gctl_value_toggle(cmdq, true);
160219

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

844+
static const struct gce_plat gce_plat_mt8196 = {
845+
.thread_nr = 32,
846+
.shift = 3,
847+
.mminfra_offset = SZ_2G,
848+
.control_by_sw = true,
849+
.sw_ddr_en = true,
850+
.gce_vm = true,
851+
.gce_num = 2
852+
};
853+
785854
static const struct of_device_id cmdq_of_ids[] = {
786855
{.compatible = "mediatek,mt6779-gce", .data = (void *)&gce_plat_mt6779},
787856
{.compatible = "mediatek,mt8173-gce", .data = (void *)&gce_plat_mt8173},
@@ -790,6 +859,7 @@ static const struct of_device_id cmdq_of_ids[] = {
790859
{.compatible = "mediatek,mt8188-gce", .data = (void *)&gce_plat_mt8188},
791860
{.compatible = "mediatek,mt8192-gce", .data = (void *)&gce_plat_mt8192},
792861
{.compatible = "mediatek,mt8195-gce", .data = (void *)&gce_plat_mt8195},
862+
{.compatible = "mediatek,mt8196-gce", .data = (void *)&gce_plat_mt8196},
793863
{}
794864
};
795865
MODULE_DEVICE_TABLE(of, cmdq_of_ids);

drivers/soc/mediatek/mtk-cmdq-helper.c

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/module.h>
99
#include <linux/mailbox_controller.h>
1010
#include <linux/of.h>
11+
#include <linux/of_address.h>
1112
#include <linux/soc/mediatek/mtk-cmdq.h>
1213

1314
#define CMDQ_WRITE_ENABLE_MASK BIT(0)
@@ -60,27 +61,51 @@ int cmdq_dev_get_client_reg(struct device *dev,
6061
struct cmdq_client_reg *client_reg, int idx)
6162
{
6263
struct of_phandle_args spec;
64+
struct resource res;
6365
int err;
6466

6567
if (!client_reg)
6668
return -ENOENT;
6769

70+
err = of_address_to_resource(dev->of_node, 0, &res);
71+
if (err) {
72+
dev_err(dev, "Missing reg in %s node\n", dev->of_node->full_name);
73+
return -EINVAL;
74+
}
75+
client_reg->pa_base = res.start;
76+
6877
err = of_parse_phandle_with_fixed_args(dev->of_node,
6978
"mediatek,gce-client-reg",
7079
3, idx, &spec);
7180
if (err < 0) {
72-
dev_warn(dev,
81+
dev_dbg(dev,
7382
"error %d can't parse gce-client-reg property (%d)",
7483
err, idx);
7584

76-
return err;
85+
/* make subsys invalid */
86+
client_reg->subsys = CMDQ_SUBSYS_INVALID;
87+
88+
/*
89+
* All GCEs support writing register PA with mask without subsys,
90+
* but this requires extra GCE instructions to convert the PA into
91+
* a format that GCE can handle, which is less performance than
92+
* directly using subsys. Therefore, when subsys is available,
93+
* we prefer to use subsys for writing register PA.
94+
*/
95+
client_reg->pkt_write = cmdq_pkt_write_pa;
96+
client_reg->pkt_write_mask = cmdq_pkt_write_mask_pa;
97+
98+
return 0;
7799
}
78100

79101
client_reg->subsys = (u8)spec.args[0];
80102
client_reg->offset = (u16)spec.args[1];
81103
client_reg->size = (u16)spec.args[2];
82104
of_node_put(spec.np);
83105

106+
client_reg->pkt_write = cmdq_pkt_write_subsys;
107+
client_reg->pkt_write_mask = cmdq_pkt_write_mask_subsys;
108+
84109
return 0;
85110
}
86111
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
140165
}
141166

142167
pkt->pa_base = dma_addr;
168+
cmdq_get_mbox_priv(client->chan, &pkt->priv);
143169

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

230+
int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
231+
u16 offset, u32 value)
232+
{
233+
int err;
234+
235+
err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
236+
if (err < 0)
237+
return err;
238+
239+
return cmdq_pkt_write_s_value(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_LOW(offset), value);
240+
}
241+
EXPORT_SYMBOL(cmdq_pkt_write_pa);
242+
243+
int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
244+
u16 offset, u32 value)
245+
{
246+
return cmdq_pkt_write(pkt, subsys, offset, value);
247+
}
248+
EXPORT_SYMBOL(cmdq_pkt_write_subsys);
249+
204250
int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
205251
u16 offset, u32 value, u32 mask)
206252
{
@@ -218,6 +264,27 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
218264
}
219265
EXPORT_SYMBOL(cmdq_pkt_write_mask);
220266

267+
int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
268+
u16 offset, u32 value, u32 mask)
269+
{
270+
int err;
271+
272+
err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
273+
if (err < 0)
274+
return err;
275+
276+
return cmdq_pkt_write_s_mask_value(pkt, CMDQ_THR_SPR_IDX0,
277+
CMDQ_ADDR_LOW(offset), value, mask);
278+
}
279+
EXPORT_SYMBOL(cmdq_pkt_write_mask_pa);
280+
281+
int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
282+
u16 offset, u32 value, u32 mask)
283+
{
284+
return cmdq_pkt_write_mask(pkt, subsys, offset, value, mask);
285+
}
286+
EXPORT_SYMBOL(cmdq_pkt_write_mask_subsys);
287+
221288
int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
222289
u16 reg_idx)
223290
{
@@ -305,6 +372,7 @@ int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_
305372
int ret;
306373

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

315383
/* write the value of value_reg_idx into dst_addr */
384+
dst_addr += pkt->priv.mminfra_offset;
316385
ret = cmdq_pkt_assign(pkt, high_addr_reg_idx, CMDQ_ADDR_HIGH(dst_addr));
317386
if (ret < 0)
318387
return ret;
@@ -438,7 +507,7 @@ int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mas
438507
inst.op = CMDQ_CODE_MASK;
439508
inst.dst_t = CMDQ_REG_TYPE;
440509
inst.sop = CMDQ_POLL_ADDR_GPR;
441-
inst.value = addr;
510+
inst.value = addr + pkt->priv.mminfra_offset;
442511
ret = cmdq_pkt_append_command(pkt, inst);
443512
if (ret < 0)
444513
return ret;
@@ -498,7 +567,7 @@ int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa)
498567
struct cmdq_instruction inst = {
499568
.op = CMDQ_CODE_JUMP,
500569
.offset = CMDQ_JUMP_ABSOLUTE,
501-
.value = addr >> shift_pa
570+
.value = (addr + pkt->priv.mminfra_offset) >> pkt->priv.shift_pa
502571
};
503572
return cmdq_pkt_append_command(pkt, inst);
504573
}

0 commit comments

Comments
 (0)