brintos

brintos / linux-shallow public Read only

0
0
Text · 10.2 KiB · 99cc791 Raw
394 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2022 Amlogic, Inc. All rights reserved.4 */5 6#include <linux/err.h>7#include <linux/io.h>8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/perf_event.h>12#include <linux/platform_device.h>13#include <linux/printk.h>14#include <linux/types.h>15 16#include <soc/amlogic/meson_ddr_pmu.h>17 18#define PORT_MAJOR		3219#define DEFAULT_XTAL_FREQ	24000000UL20 21#define DMC_QOS_IRQ		BIT(30)22 23/* DMC bandwidth monitor register address offset */24#define DMC_MON_G12_CTRL0		(0x0  << 2)25#define DMC_MON_G12_CTRL1		(0x1  << 2)26#define DMC_MON_G12_CTRL2		(0x2  << 2)27#define DMC_MON_G12_CTRL3		(0x3  << 2)28#define DMC_MON_G12_CTRL4		(0x4  << 2)29#define DMC_MON_G12_CTRL5		(0x5  << 2)30#define DMC_MON_G12_CTRL6		(0x6  << 2)31#define DMC_MON_G12_CTRL7		(0x7  << 2)32#define DMC_MON_G12_CTRL8		(0x8  << 2)33 34#define DMC_MON_G12_ALL_REQ_CNT		(0x9  << 2)35#define DMC_MON_G12_ALL_GRANT_CNT	(0xa  << 2)36#define DMC_MON_G12_ONE_GRANT_CNT	(0xb  << 2)37#define DMC_MON_G12_SEC_GRANT_CNT	(0xc  << 2)38#define DMC_MON_G12_THD_GRANT_CNT	(0xd  << 2)39#define DMC_MON_G12_FOR_GRANT_CNT	(0xe  << 2)40#define DMC_MON_G12_TIMER		(0xf  << 2)41 42/* Each bit represent a axi line */43PMU_FORMAT_ATTR(event, "config:0-7");44PMU_FORMAT_ATTR(arm, "config1:0");45PMU_FORMAT_ATTR(gpu, "config1:1");46PMU_FORMAT_ATTR(pcie, "config1:2");47PMU_FORMAT_ATTR(hdcp, "config1:3");48PMU_FORMAT_ATTR(hevc_front, "config1:4");49PMU_FORMAT_ATTR(usb3_0, "config1:6");50PMU_FORMAT_ATTR(device, "config1:7");51PMU_FORMAT_ATTR(hevc_back, "config1:8");52PMU_FORMAT_ATTR(h265enc, "config1:9");53PMU_FORMAT_ATTR(vpu_read1, "config1:16");54PMU_FORMAT_ATTR(vpu_read2, "config1:17");55PMU_FORMAT_ATTR(vpu_read3, "config1:18");56PMU_FORMAT_ATTR(vpu_write1, "config1:19");57PMU_FORMAT_ATTR(vpu_write2, "config1:20");58PMU_FORMAT_ATTR(vdec, "config1:21");59PMU_FORMAT_ATTR(hcodec, "config1:22");60PMU_FORMAT_ATTR(ge2d, "config1:23");61 62PMU_FORMAT_ATTR(spicc1, "config1:32");63PMU_FORMAT_ATTR(usb0, "config1:33");64PMU_FORMAT_ATTR(dma, "config1:34");65PMU_FORMAT_ATTR(arb0, "config1:35");66PMU_FORMAT_ATTR(sd_emmc_b, "config1:36");67PMU_FORMAT_ATTR(usb1, "config1:37");68PMU_FORMAT_ATTR(audio, "config1:38");69PMU_FORMAT_ATTR(aififo, "config1:39");70PMU_FORMAT_ATTR(parser, "config1:41");71PMU_FORMAT_ATTR(ao_cpu, "config1:42");72PMU_FORMAT_ATTR(sd_emmc_c, "config1:43");73PMU_FORMAT_ATTR(spicc2, "config1:44");74PMU_FORMAT_ATTR(ethernet, "config1:45");75PMU_FORMAT_ATTR(sana, "config1:46");76 77/* for sm1 and g12b */78PMU_FORMAT_ATTR(nna, "config1:10");79 80/* for g12b only */81PMU_FORMAT_ATTR(gdc, "config1:11");82PMU_FORMAT_ATTR(mipi_isp, "config1:12");83PMU_FORMAT_ATTR(arm1, "config1:13");84PMU_FORMAT_ATTR(sd_emmc_a, "config1:40");85 86static struct attribute *g12_pmu_format_attrs[] = {87	&format_attr_event.attr,88	&format_attr_arm.attr,89	&format_attr_gpu.attr,90	&format_attr_nna.attr,91	&format_attr_gdc.attr,92	&format_attr_arm1.attr,93	&format_attr_mipi_isp.attr,94	&format_attr_sd_emmc_a.attr,95	&format_attr_pcie.attr,96	&format_attr_hdcp.attr,97	&format_attr_hevc_front.attr,98	&format_attr_usb3_0.attr,99	&format_attr_device.attr,100	&format_attr_hevc_back.attr,101	&format_attr_h265enc.attr,102	&format_attr_vpu_read1.attr,103	&format_attr_vpu_read2.attr,104	&format_attr_vpu_read3.attr,105	&format_attr_vpu_write1.attr,106	&format_attr_vpu_write2.attr,107	&format_attr_vdec.attr,108	&format_attr_hcodec.attr,109	&format_attr_ge2d.attr,110	&format_attr_spicc1.attr,111	&format_attr_usb0.attr,112	&format_attr_dma.attr,113	&format_attr_arb0.attr,114	&format_attr_sd_emmc_b.attr,115	&format_attr_usb1.attr,116	&format_attr_audio.attr,117	&format_attr_aififo.attr,118	&format_attr_parser.attr,119	&format_attr_ao_cpu.attr,120	&format_attr_sd_emmc_c.attr,121	&format_attr_spicc2.attr,122	&format_attr_ethernet.attr,123	&format_attr_sana.attr,124	NULL,125};126 127/* calculate ddr clock */128static unsigned long dmc_g12_get_freq_quick(struct dmc_info *info)129{130	unsigned int val;131	unsigned int n, m, od1;132	unsigned int od_div = 0xfff;133	unsigned long freq = 0;134 135	val = readl(info->pll_reg);136	val = val & 0xfffff;137	switch ((val >> 16) & 7) {138	case 0:139		od_div = 2;140		break;141 142	case 1:143		od_div = 3;144		break;145 146	case 2:147		od_div = 4;148		break;149 150	case 3:151		od_div = 6;152		break;153 154	case 4:155		od_div = 8;156		break;157 158	default:159		break;160	}161 162	m = val & 0x1ff;163	n = ((val >> 10) & 0x1f);164	od1 = (((val >> 19) & 0x1)) == 1 ? 2 : 1;165	freq = DEFAULT_XTAL_FREQ / 1000;        /* avoid overflow */166	if (n)167		freq = ((((freq * m) / n) >> od1) / od_div) * 1000;168 169	return freq;170}171 172#ifdef DEBUG173static void g12_dump_reg(struct dmc_info *db)174{175	int s = 0, i;176	unsigned int r;177 178	for (i = 0; i < 9; i++) {179		r  = readl(db->ddr_reg[0] + (DMC_MON_G12_CTRL0 + (i << 2)));180		pr_notice("DMC_MON_CTRL%d:        %08x\n", i, r);181	}182	r  = readl(db->ddr_reg[0] + DMC_MON_G12_ALL_REQ_CNT);183	pr_notice("DMC_MON_ALL_REQ_CNT:  %08x\n", r);184	r  = readl(db->ddr_reg[0] + DMC_MON_G12_ALL_GRANT_CNT);185	pr_notice("DMC_MON_ALL_GRANT_CNT:%08x\n", r);186	r  = readl(db->ddr_reg[0] + DMC_MON_G12_ONE_GRANT_CNT);187	pr_notice("DMC_MON_ONE_GRANT_CNT:%08x\n", r);188	r  = readl(db->ddr_reg[0] + DMC_MON_G12_SEC_GRANT_CNT);189	pr_notice("DMC_MON_SEC_GRANT_CNT:%08x\n", r);190	r  = readl(db->ddr_reg[0] + DMC_MON_G12_THD_GRANT_CNT);191	pr_notice("DMC_MON_THD_GRANT_CNT:%08x\n", r);192	r  = readl(db->ddr_reg[0] + DMC_MON_G12_FOR_GRANT_CNT);193	pr_notice("DMC_MON_FOR_GRANT_CNT:%08x\n", r);194	r  = readl(db->ddr_reg[0] + DMC_MON_G12_TIMER);195	pr_notice("DMC_MON_TIMER:        %08x\n", r);196}197#endif198 199static void dmc_g12_counter_enable(struct dmc_info *info)200{201	unsigned int val;202	unsigned long clock_count = dmc_g12_get_freq_quick(info) / 10; /* 100ms */203 204	writel(clock_count, info->ddr_reg[0] + DMC_MON_G12_TIMER);205 206	val = readl(info->ddr_reg[0] + DMC_MON_G12_CTRL0);207 208	/* enable all channel */209	val =  BIT(31) |	/* enable bit */210	       BIT(20) |	/* use timer  */211	       0x0f;		/* 4 channels */212 213	writel(val, info->ddr_reg[0] + DMC_MON_G12_CTRL0);214 215#ifdef DEBUG216	g12_dump_reg(info);217#endif218}219 220static void dmc_g12_config_fiter(struct dmc_info *info,221				 int port, int channel)222{223	u32 val;224	u32 rp[MAX_CHANNEL_NUM] = {DMC_MON_G12_CTRL1, DMC_MON_G12_CTRL3,225					DMC_MON_G12_CTRL5, DMC_MON_G12_CTRL7};226	u32 rs[MAX_CHANNEL_NUM] = {DMC_MON_G12_CTRL2, DMC_MON_G12_CTRL4,227					DMC_MON_G12_CTRL6, DMC_MON_G12_CTRL8};228	int subport = -1;229 230	/* clear all port mask */231	if (port < 0) {232		writel(0, info->ddr_reg[0] + rp[channel]);233		writel(0, info->ddr_reg[0] + rs[channel]);234		return;235	}236 237	if (port >= PORT_MAJOR)238		subport = port - PORT_MAJOR;239 240	if (subport < 0) {241		val = readl(info->ddr_reg[0] + rp[channel]);242		val |=  (1 << port);243		writel(val, info->ddr_reg[0] + rp[channel]);244		val = 0xffff;245		writel(val, info->ddr_reg[0] + rs[channel]);246	} else {247		val = BIT(23);		/* select device */248		writel(val, info->ddr_reg[0] + rp[channel]);249		val = readl(info->ddr_reg[0] + rs[channel]);250		val |= (1 << subport);251		writel(val, info->ddr_reg[0] + rs[channel]);252	}253}254 255static void dmc_g12_set_axi_filter(struct dmc_info *info, int axi_id, int channel)256{257	if (channel > info->hw_info->chann_nr)258		return;259 260	dmc_g12_config_fiter(info, axi_id, channel);261}262 263static void dmc_g12_counter_disable(struct dmc_info *info)264{265	int i;266 267	/* clear timer */268	writel(0, info->ddr_reg[0] + DMC_MON_G12_CTRL0);269	writel(0, info->ddr_reg[0] + DMC_MON_G12_TIMER);270 271	writel(0, info->ddr_reg[0] + DMC_MON_G12_ALL_REQ_CNT);272	writel(0, info->ddr_reg[0] + DMC_MON_G12_ALL_GRANT_CNT);273	writel(0, info->ddr_reg[0] + DMC_MON_G12_ONE_GRANT_CNT);274	writel(0, info->ddr_reg[0] + DMC_MON_G12_SEC_GRANT_CNT);275	writel(0, info->ddr_reg[0] + DMC_MON_G12_THD_GRANT_CNT);276	writel(0, info->ddr_reg[0] + DMC_MON_G12_FOR_GRANT_CNT);277 278	/* clear port channel mapping */279	for (i = 0; i < info->hw_info->chann_nr; i++)280		dmc_g12_config_fiter(info, -1, i);281}282 283static void dmc_g12_get_counters(struct dmc_info *info,284				 struct dmc_counter *counter)285{286	int i;287	unsigned int reg;288 289	counter->all_cnt = readl(info->ddr_reg[0] + DMC_MON_G12_ALL_GRANT_CNT);290	counter->all_req   = readl(info->ddr_reg[0] + DMC_MON_G12_ALL_REQ_CNT);291 292	for (i = 0; i < info->hw_info->chann_nr; i++) {293		reg = DMC_MON_G12_ONE_GRANT_CNT + (i << 2);294		counter->channel_cnt[i] = readl(info->ddr_reg[0] + reg);295	}296}297 298static int dmc_g12_irq_handler(struct dmc_info *info,299			       struct dmc_counter *counter)300{301	unsigned int val;302	int ret = -EINVAL;303 304	val = readl(info->ddr_reg[0] + DMC_MON_G12_CTRL0);305	if (val & DMC_QOS_IRQ) {306		dmc_g12_get_counters(info, counter);307		/* clear irq flags */308		writel(val, info->ddr_reg[0] + DMC_MON_G12_CTRL0);309		ret = 0;310	}311	return ret;312}313 314static const struct dmc_hw_info g12a_dmc_info = {315	.enable		= dmc_g12_counter_enable,316	.disable	= dmc_g12_counter_disable,317	.irq_handler	= dmc_g12_irq_handler,318	.get_counters	= dmc_g12_get_counters,319	.set_axi_filter	= dmc_g12_set_axi_filter,320 321	.dmc_nr = 1,322	.chann_nr = 4,323	.capability = {0X7EFF00FF03DF, 0},324	.fmt_attr = g12_pmu_format_attrs,325};326 327static const struct dmc_hw_info g12b_dmc_info = {328	.enable		= dmc_g12_counter_enable,329	.disable	= dmc_g12_counter_disable,330	.irq_handler	= dmc_g12_irq_handler,331	.get_counters	= dmc_g12_get_counters,332	.set_axi_filter	= dmc_g12_set_axi_filter,333 334	.dmc_nr = 1,335	.chann_nr = 4,336	.capability = {0X7FFF00FF3FDF, 0},337	.fmt_attr = g12_pmu_format_attrs,338};339 340static const struct dmc_hw_info sm1_dmc_info = {341	.enable		= dmc_g12_counter_enable,342	.disable	= dmc_g12_counter_disable,343	.irq_handler	= dmc_g12_irq_handler,344	.get_counters	= dmc_g12_get_counters,345	.set_axi_filter	= dmc_g12_set_axi_filter,346 347	.dmc_nr = 1,348	.chann_nr = 4,349	.capability = {0X7EFF00FF07DF, 0},350	.fmt_attr = g12_pmu_format_attrs,351};352 353static int g12_ddr_pmu_probe(struct platform_device *pdev)354{355	return meson_ddr_pmu_create(pdev);356}357 358static void g12_ddr_pmu_remove(struct platform_device *pdev)359{360	meson_ddr_pmu_remove(pdev);361}362 363static const struct of_device_id meson_ddr_pmu_dt_match[] = {364	{365		.compatible = "amlogic,g12a-ddr-pmu",366		.data = &g12a_dmc_info,367	},368	{369		.compatible = "amlogic,g12b-ddr-pmu",370		.data = &g12b_dmc_info,371	},372	{373		.compatible = "amlogic,sm1-ddr-pmu",374		.data = &sm1_dmc_info,375	},376	{}377};378MODULE_DEVICE_TABLE(of, meson_ddr_pmu_dt_match);379 380static struct platform_driver g12_ddr_pmu_driver = {381	.probe = g12_ddr_pmu_probe,382	.remove_new = g12_ddr_pmu_remove,383 384	.driver = {385		.name = "meson-g12-ddr-pmu",386		.of_match_table = meson_ddr_pmu_dt_match,387	},388};389 390module_platform_driver(g12_ddr_pmu_driver);391MODULE_AUTHOR("Jiucheng Xu");392MODULE_LICENSE("GPL");393MODULE_DESCRIPTION("Amlogic G12 series SoC DDR PMU");394