18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2009-2010, 2012 Freescale Semiconductor, Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
138c2ecf20Sopenharmony_ci#include <asm/io.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "fsl_85xx_cache_ctlr.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic char *sram_size;
188c2ecf20Sopenharmony_cistatic char *sram_offset;
198c2ecf20Sopenharmony_cistruct mpc85xx_l2ctlr __iomem *l2ctlr;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic int get_cache_sram_params(struct sram_parameters *sram_params)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	unsigned long long addr;
248c2ecf20Sopenharmony_ci	unsigned int size;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (!sram_size || (kstrtouint(sram_size, 0, &size) < 0))
278c2ecf20Sopenharmony_ci		return -EINVAL;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	if (!sram_offset || (kstrtoull(sram_offset, 0, &addr) < 0))
308c2ecf20Sopenharmony_ci		return -EINVAL;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	sram_params->sram_offset = addr;
338c2ecf20Sopenharmony_ci	sram_params->sram_size = size;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return 0;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int __init get_size_from_cmdline(char *str)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	if (!str)
418c2ecf20Sopenharmony_ci		return 0;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	sram_size = str;
448c2ecf20Sopenharmony_ci	return 1;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int __init get_offset_from_cmdline(char *str)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	if (!str)
508c2ecf20Sopenharmony_ci		return 0;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	sram_offset = str;
538c2ecf20Sopenharmony_ci	return 1;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci__setup("cache-sram-size=", get_size_from_cmdline);
578c2ecf20Sopenharmony_ci__setup("cache-sram-offset=", get_offset_from_cmdline);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	long rval;
628c2ecf20Sopenharmony_ci	unsigned int rem;
638c2ecf20Sopenharmony_ci	unsigned char ways;
648c2ecf20Sopenharmony_ci	const unsigned int *prop;
658c2ecf20Sopenharmony_ci	unsigned int l2cache_size;
668c2ecf20Sopenharmony_ci	struct sram_parameters sram_params;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (!dev->dev.of_node) {
698c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Device's OF-node is NULL\n");
708c2ecf20Sopenharmony_ci		return -EINVAL;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	prop = of_get_property(dev->dev.of_node, "cache-size", NULL);
748c2ecf20Sopenharmony_ci	if (!prop) {
758c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Missing L2 cache-size\n");
768c2ecf20Sopenharmony_ci		return -EINVAL;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci	l2cache_size = *prop;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (get_cache_sram_params(&sram_params))
818c2ecf20Sopenharmony_ci		return 0; /* fall back to L2 cache only */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	rem = l2cache_size % sram_params.sram_size;
848c2ecf20Sopenharmony_ci	ways = LOCK_WAYS_FULL * sram_params.sram_size / l2cache_size;
858c2ecf20Sopenharmony_ci	if (rem || (ways & (ways - 1))) {
868c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Illegal cache-sram-size in command line\n");
878c2ecf20Sopenharmony_ci		return -EINVAL;
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	l2ctlr = of_iomap(dev->dev.of_node, 0);
918c2ecf20Sopenharmony_ci	if (!l2ctlr) {
928c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Can't map L2 controller\n");
938c2ecf20Sopenharmony_ci		return -EINVAL;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/*
978c2ecf20Sopenharmony_ci	 * Write bits[0-17] to srbar0
988c2ecf20Sopenharmony_ci	 */
998c2ecf20Sopenharmony_ci	out_be32(&l2ctlr->srbar0,
1008c2ecf20Sopenharmony_ci		lower_32_bits(sram_params.sram_offset) & L2SRAM_BAR_MSK_LO18);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/*
1038c2ecf20Sopenharmony_ci	 * Write bits[18-21] to srbare0
1048c2ecf20Sopenharmony_ci	 */
1058c2ecf20Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT
1068c2ecf20Sopenharmony_ci	out_be32(&l2ctlr->srbarea0,
1078c2ecf20Sopenharmony_ci		upper_32_bits(sram_params.sram_offset) & L2SRAM_BARE_MSK_HI4);
1088c2ecf20Sopenharmony_ci#endif
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	switch (ways) {
1138c2ecf20Sopenharmony_ci	case LOCK_WAYS_EIGHTH:
1148c2ecf20Sopenharmony_ci		setbits32(&l2ctlr->ctl,
1158c2ecf20Sopenharmony_ci			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH);
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	case LOCK_WAYS_TWO_EIGHTH:
1198c2ecf20Sopenharmony_ci		setbits32(&l2ctlr->ctl,
1208c2ecf20Sopenharmony_ci			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART);
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	case LOCK_WAYS_HALF:
1248c2ecf20Sopenharmony_ci		setbits32(&l2ctlr->ctl,
1258c2ecf20Sopenharmony_ci			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF);
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	case LOCK_WAYS_FULL:
1298c2ecf20Sopenharmony_ci	default:
1308c2ecf20Sopenharmony_ci		setbits32(&l2ctlr->ctl,
1318c2ecf20Sopenharmony_ci			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL);
1328c2ecf20Sopenharmony_ci		break;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci	eieio();
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	rval = instantiate_cache_sram(dev, sram_params);
1378c2ecf20Sopenharmony_ci	if (rval < 0) {
1388c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Can't instantiate Cache-SRAM\n");
1398c2ecf20Sopenharmony_ci		iounmap(l2ctlr);
1408c2ecf20Sopenharmony_ci		return -EINVAL;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return 0;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic int mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	BUG_ON(!l2ctlr);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	iounmap(l2ctlr);
1518c2ecf20Sopenharmony_ci	remove_cache_sram(dev);
1528c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "MPC85xx L2 controller unloaded\n");
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	return 0;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic const struct of_device_id mpc85xx_l2ctlr_of_match[] = {
1588c2ecf20Sopenharmony_ci	{
1598c2ecf20Sopenharmony_ci		.compatible = "fsl,p2020-l2-cache-controller",
1608c2ecf20Sopenharmony_ci	},
1618c2ecf20Sopenharmony_ci	{
1628c2ecf20Sopenharmony_ci		.compatible = "fsl,p2010-l2-cache-controller",
1638c2ecf20Sopenharmony_ci	},
1648c2ecf20Sopenharmony_ci	{
1658c2ecf20Sopenharmony_ci		.compatible = "fsl,p1020-l2-cache-controller",
1668c2ecf20Sopenharmony_ci	},
1678c2ecf20Sopenharmony_ci	{
1688c2ecf20Sopenharmony_ci		.compatible = "fsl,p1011-l2-cache-controller",
1698c2ecf20Sopenharmony_ci	},
1708c2ecf20Sopenharmony_ci	{
1718c2ecf20Sopenharmony_ci		.compatible = "fsl,p1013-l2-cache-controller",
1728c2ecf20Sopenharmony_ci	},
1738c2ecf20Sopenharmony_ci	{
1748c2ecf20Sopenharmony_ci		.compatible = "fsl,p1022-l2-cache-controller",
1758c2ecf20Sopenharmony_ci	},
1768c2ecf20Sopenharmony_ci	{
1778c2ecf20Sopenharmony_ci		.compatible = "fsl,mpc8548-l2-cache-controller",
1788c2ecf20Sopenharmony_ci	},
1798c2ecf20Sopenharmony_ci	{	.compatible = "fsl,mpc8544-l2-cache-controller",},
1808c2ecf20Sopenharmony_ci	{	.compatible = "fsl,mpc8572-l2-cache-controller",},
1818c2ecf20Sopenharmony_ci	{	.compatible = "fsl,mpc8536-l2-cache-controller",},
1828c2ecf20Sopenharmony_ci	{	.compatible = "fsl,p1021-l2-cache-controller",},
1838c2ecf20Sopenharmony_ci	{	.compatible = "fsl,p1012-l2-cache-controller",},
1848c2ecf20Sopenharmony_ci	{	.compatible = "fsl,p1025-l2-cache-controller",},
1858c2ecf20Sopenharmony_ci	{	.compatible = "fsl,p1016-l2-cache-controller",},
1868c2ecf20Sopenharmony_ci	{	.compatible = "fsl,p1024-l2-cache-controller",},
1878c2ecf20Sopenharmony_ci	{	.compatible = "fsl,p1015-l2-cache-controller",},
1888c2ecf20Sopenharmony_ci	{	.compatible = "fsl,p1010-l2-cache-controller",},
1898c2ecf20Sopenharmony_ci	{	.compatible = "fsl,bsc9131-l2-cache-controller",},
1908c2ecf20Sopenharmony_ci	{},
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic struct platform_driver mpc85xx_l2ctlr_of_platform_driver = {
1948c2ecf20Sopenharmony_ci	.driver	= {
1958c2ecf20Sopenharmony_ci		.name		= "fsl-l2ctlr",
1968c2ecf20Sopenharmony_ci		.of_match_table	= mpc85xx_l2ctlr_of_match,
1978c2ecf20Sopenharmony_ci	},
1988c2ecf20Sopenharmony_ci	.probe		= mpc85xx_l2ctlr_of_probe,
1998c2ecf20Sopenharmony_ci	.remove		= mpc85xx_l2ctlr_of_remove,
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic __init int mpc85xx_l2ctlr_of_init(void)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	return platform_driver_register(&mpc85xx_l2ctlr_of_platform_driver);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic void __exit mpc85xx_l2ctlr_of_exit(void)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	platform_driver_unregister(&mpc85xx_l2ctlr_of_platform_driver);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cisubsys_initcall(mpc85xx_l2ctlr_of_init);
2138c2ecf20Sopenharmony_cimodule_exit(mpc85xx_l2ctlr_of_exit);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Freescale MPC85xx L2 controller init");
2168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
217