1353a0f1dSLuo Jie // SPDX-License-Identifier: GPL-2.0-only 2353a0f1dSLuo Jie /* 3353a0f1dSLuo Jie * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 4353a0f1dSLuo Jie */ 5353a0f1dSLuo Jie 6353a0f1dSLuo Jie /* PPE platform device probe, DTSI parser and PPE clock initializations. */ 7353a0f1dSLuo Jie 8353a0f1dSLuo Jie #include <linux/clk.h> 9353a0f1dSLuo Jie #include <linux/interconnect.h> 10353a0f1dSLuo Jie #include <linux/kernel.h> 11353a0f1dSLuo Jie #include <linux/module.h> 12353a0f1dSLuo Jie #include <linux/of.h> 13353a0f1dSLuo Jie #include <linux/platform_device.h> 14353a0f1dSLuo Jie #include <linux/regmap.h> 15353a0f1dSLuo Jie #include <linux/reset.h> 16353a0f1dSLuo Jie 17353a0f1dSLuo Jie #include "ppe.h" 188a971df9SLuo Jie #include "ppe_config.h" 19*a2a7221dSLuo Jie #include "ppe_debugfs.h" 20353a0f1dSLuo Jie 21353a0f1dSLuo Jie #define PPE_PORT_MAX 8 22353a0f1dSLuo Jie #define PPE_CLK_RATE 353000000 23353a0f1dSLuo Jie 24353a0f1dSLuo Jie /* ICC clocks for enabling PPE device. The avg_bw and peak_bw with value 0 25353a0f1dSLuo Jie * will be updated by the clock rate of PPE. 26353a0f1dSLuo Jie */ 27353a0f1dSLuo Jie static const struct icc_bulk_data ppe_icc_data[] = { 28353a0f1dSLuo Jie { 29353a0f1dSLuo Jie .name = "ppe", 30353a0f1dSLuo Jie .avg_bw = 0, 31353a0f1dSLuo Jie .peak_bw = 0, 32353a0f1dSLuo Jie }, 33353a0f1dSLuo Jie { 34353a0f1dSLuo Jie .name = "ppe_cfg", 35353a0f1dSLuo Jie .avg_bw = 0, 36353a0f1dSLuo Jie .peak_bw = 0, 37353a0f1dSLuo Jie }, 38353a0f1dSLuo Jie { 39353a0f1dSLuo Jie .name = "qos_gen", 40353a0f1dSLuo Jie .avg_bw = 6000, 41353a0f1dSLuo Jie .peak_bw = 6000, 42353a0f1dSLuo Jie }, 43353a0f1dSLuo Jie { 44353a0f1dSLuo Jie .name = "timeout_ref", 45353a0f1dSLuo Jie .avg_bw = 6000, 46353a0f1dSLuo Jie .peak_bw = 6000, 47353a0f1dSLuo Jie }, 48353a0f1dSLuo Jie { 49353a0f1dSLuo Jie .name = "nssnoc_memnoc", 50353a0f1dSLuo Jie .avg_bw = 533333, 51353a0f1dSLuo Jie .peak_bw = 533333, 52353a0f1dSLuo Jie }, 53353a0f1dSLuo Jie { 54353a0f1dSLuo Jie .name = "memnoc_nssnoc", 55353a0f1dSLuo Jie .avg_bw = 533333, 56353a0f1dSLuo Jie .peak_bw = 533333, 57353a0f1dSLuo Jie }, 58353a0f1dSLuo Jie { 59353a0f1dSLuo Jie .name = "memnoc_nssnoc_1", 60353a0f1dSLuo Jie .avg_bw = 533333, 61353a0f1dSLuo Jie .peak_bw = 533333, 62353a0f1dSLuo Jie }, 63353a0f1dSLuo Jie }; 64353a0f1dSLuo Jie 65353a0f1dSLuo Jie static const struct regmap_range ppe_readable_ranges[] = { 66353a0f1dSLuo Jie regmap_reg_range(0x0, 0x1ff), /* Global */ 67353a0f1dSLuo Jie regmap_reg_range(0x400, 0x5ff), /* LPI CSR */ 68353a0f1dSLuo Jie regmap_reg_range(0x1000, 0x11ff), /* GMAC0 */ 69353a0f1dSLuo Jie regmap_reg_range(0x1200, 0x13ff), /* GMAC1 */ 70353a0f1dSLuo Jie regmap_reg_range(0x1400, 0x15ff), /* GMAC2 */ 71353a0f1dSLuo Jie regmap_reg_range(0x1600, 0x17ff), /* GMAC3 */ 72353a0f1dSLuo Jie regmap_reg_range(0x1800, 0x19ff), /* GMAC4 */ 73353a0f1dSLuo Jie regmap_reg_range(0x1a00, 0x1bff), /* GMAC5 */ 74353a0f1dSLuo Jie regmap_reg_range(0xb000, 0xefff), /* PRX CSR */ 75353a0f1dSLuo Jie regmap_reg_range(0xf000, 0x1efff), /* IPE */ 76353a0f1dSLuo Jie regmap_reg_range(0x20000, 0x5ffff), /* PTX CSR */ 77353a0f1dSLuo Jie regmap_reg_range(0x60000, 0x9ffff), /* IPE L2 CSR */ 78353a0f1dSLuo Jie regmap_reg_range(0xb0000, 0xeffff), /* IPO CSR */ 79353a0f1dSLuo Jie regmap_reg_range(0x100000, 0x17ffff), /* IPE PC */ 80353a0f1dSLuo Jie regmap_reg_range(0x180000, 0x1bffff), /* PRE IPO CSR */ 81353a0f1dSLuo Jie regmap_reg_range(0x1d0000, 0x1dffff), /* Tunnel parser */ 82353a0f1dSLuo Jie regmap_reg_range(0x1e0000, 0x1effff), /* Ingress parse */ 83353a0f1dSLuo Jie regmap_reg_range(0x200000, 0x2fffff), /* IPE L3 */ 84353a0f1dSLuo Jie regmap_reg_range(0x300000, 0x3fffff), /* IPE tunnel */ 85353a0f1dSLuo Jie regmap_reg_range(0x400000, 0x4fffff), /* Scheduler */ 86353a0f1dSLuo Jie regmap_reg_range(0x500000, 0x503fff), /* XGMAC0 */ 87353a0f1dSLuo Jie regmap_reg_range(0x504000, 0x507fff), /* XGMAC1 */ 88353a0f1dSLuo Jie regmap_reg_range(0x508000, 0x50bfff), /* XGMAC2 */ 89353a0f1dSLuo Jie regmap_reg_range(0x50c000, 0x50ffff), /* XGMAC3 */ 90353a0f1dSLuo Jie regmap_reg_range(0x510000, 0x513fff), /* XGMAC4 */ 91353a0f1dSLuo Jie regmap_reg_range(0x514000, 0x517fff), /* XGMAC5 */ 92353a0f1dSLuo Jie regmap_reg_range(0x600000, 0x6fffff), /* BM */ 93353a0f1dSLuo Jie regmap_reg_range(0x800000, 0x9fffff), /* QM */ 94353a0f1dSLuo Jie regmap_reg_range(0xb00000, 0xbef800), /* EDMA */ 95353a0f1dSLuo Jie }; 96353a0f1dSLuo Jie 97353a0f1dSLuo Jie static const struct regmap_access_table ppe_reg_table = { 98353a0f1dSLuo Jie .yes_ranges = ppe_readable_ranges, 99353a0f1dSLuo Jie .n_yes_ranges = ARRAY_SIZE(ppe_readable_ranges), 100353a0f1dSLuo Jie }; 101353a0f1dSLuo Jie 102353a0f1dSLuo Jie static const struct regmap_config regmap_config_ipq9574 = { 103353a0f1dSLuo Jie .reg_bits = 32, 104353a0f1dSLuo Jie .reg_stride = 4, 105353a0f1dSLuo Jie .val_bits = 32, 106353a0f1dSLuo Jie .rd_table = &ppe_reg_table, 107353a0f1dSLuo Jie .wr_table = &ppe_reg_table, 108353a0f1dSLuo Jie .max_register = 0xbef800, 109353a0f1dSLuo Jie .fast_io = true, 110353a0f1dSLuo Jie }; 111353a0f1dSLuo Jie 112353a0f1dSLuo Jie static int ppe_clock_init_and_reset(struct ppe_device *ppe_dev) 113353a0f1dSLuo Jie { 114353a0f1dSLuo Jie unsigned long ppe_rate = ppe_dev->clk_rate; 115353a0f1dSLuo Jie struct device *dev = ppe_dev->dev; 116353a0f1dSLuo Jie struct reset_control *rstc; 117353a0f1dSLuo Jie struct clk_bulk_data *clks; 118353a0f1dSLuo Jie struct clk *clk; 119353a0f1dSLuo Jie int ret, i; 120353a0f1dSLuo Jie 121353a0f1dSLuo Jie for (i = 0; i < ppe_dev->num_icc_paths; i++) { 122353a0f1dSLuo Jie ppe_dev->icc_paths[i].name = ppe_icc_data[i].name; 123353a0f1dSLuo Jie ppe_dev->icc_paths[i].avg_bw = ppe_icc_data[i].avg_bw ? : 124353a0f1dSLuo Jie Bps_to_icc(ppe_rate); 125353a0f1dSLuo Jie 126353a0f1dSLuo Jie /* PPE does not have an explicit peak bandwidth requirement, 127353a0f1dSLuo Jie * so set the peak bandwidth to be equal to the average 128353a0f1dSLuo Jie * bandwidth. 129353a0f1dSLuo Jie */ 130353a0f1dSLuo Jie ppe_dev->icc_paths[i].peak_bw = ppe_icc_data[i].peak_bw ? : 131353a0f1dSLuo Jie Bps_to_icc(ppe_rate); 132353a0f1dSLuo Jie } 133353a0f1dSLuo Jie 134353a0f1dSLuo Jie ret = devm_of_icc_bulk_get(dev, ppe_dev->num_icc_paths, 135353a0f1dSLuo Jie ppe_dev->icc_paths); 136353a0f1dSLuo Jie if (ret) 137353a0f1dSLuo Jie return ret; 138353a0f1dSLuo Jie 139353a0f1dSLuo Jie ret = icc_bulk_set_bw(ppe_dev->num_icc_paths, ppe_dev->icc_paths); 140353a0f1dSLuo Jie if (ret) 141353a0f1dSLuo Jie return ret; 142353a0f1dSLuo Jie 143353a0f1dSLuo Jie /* The PPE clocks have a common parent clock. Setting the clock 144353a0f1dSLuo Jie * rate of "ppe" ensures the clock rate of all PPE clocks is 145353a0f1dSLuo Jie * configured to the same rate. 146353a0f1dSLuo Jie */ 147353a0f1dSLuo Jie clk = devm_clk_get(dev, "ppe"); 148353a0f1dSLuo Jie if (IS_ERR(clk)) 149353a0f1dSLuo Jie return PTR_ERR(clk); 150353a0f1dSLuo Jie 151353a0f1dSLuo Jie ret = clk_set_rate(clk, ppe_rate); 152353a0f1dSLuo Jie if (ret) 153353a0f1dSLuo Jie return ret; 154353a0f1dSLuo Jie 155353a0f1dSLuo Jie ret = devm_clk_bulk_get_all_enabled(dev, &clks); 156353a0f1dSLuo Jie if (ret < 0) 157353a0f1dSLuo Jie return ret; 158353a0f1dSLuo Jie 159353a0f1dSLuo Jie /* Reset the PPE. */ 160353a0f1dSLuo Jie rstc = devm_reset_control_get_exclusive(dev, NULL); 161353a0f1dSLuo Jie if (IS_ERR(rstc)) 162353a0f1dSLuo Jie return PTR_ERR(rstc); 163353a0f1dSLuo Jie 164353a0f1dSLuo Jie ret = reset_control_assert(rstc); 165353a0f1dSLuo Jie if (ret) 166353a0f1dSLuo Jie return ret; 167353a0f1dSLuo Jie 168353a0f1dSLuo Jie /* The delay 10 ms of assert is necessary for resetting PPE. */ 169353a0f1dSLuo Jie usleep_range(10000, 11000); 170353a0f1dSLuo Jie 171353a0f1dSLuo Jie return reset_control_deassert(rstc); 172353a0f1dSLuo Jie } 173353a0f1dSLuo Jie 174353a0f1dSLuo Jie static int qcom_ppe_probe(struct platform_device *pdev) 175353a0f1dSLuo Jie { 176353a0f1dSLuo Jie struct device *dev = &pdev->dev; 177353a0f1dSLuo Jie struct ppe_device *ppe_dev; 178353a0f1dSLuo Jie void __iomem *base; 179353a0f1dSLuo Jie int ret, num_icc; 180353a0f1dSLuo Jie 181353a0f1dSLuo Jie num_icc = ARRAY_SIZE(ppe_icc_data); 182353a0f1dSLuo Jie ppe_dev = devm_kzalloc(dev, struct_size(ppe_dev, icc_paths, num_icc), 183353a0f1dSLuo Jie GFP_KERNEL); 184353a0f1dSLuo Jie if (!ppe_dev) 185353a0f1dSLuo Jie return -ENOMEM; 186353a0f1dSLuo Jie 187353a0f1dSLuo Jie base = devm_platform_ioremap_resource(pdev, 0); 188353a0f1dSLuo Jie if (IS_ERR(base)) 189353a0f1dSLuo Jie return dev_err_probe(dev, PTR_ERR(base), "PPE ioremap failed\n"); 190353a0f1dSLuo Jie 191353a0f1dSLuo Jie ppe_dev->regmap = devm_regmap_init_mmio(dev, base, ®map_config_ipq9574); 192353a0f1dSLuo Jie if (IS_ERR(ppe_dev->regmap)) 193353a0f1dSLuo Jie return dev_err_probe(dev, PTR_ERR(ppe_dev->regmap), 194353a0f1dSLuo Jie "PPE initialize regmap failed\n"); 195353a0f1dSLuo Jie ppe_dev->dev = dev; 196353a0f1dSLuo Jie ppe_dev->clk_rate = PPE_CLK_RATE; 197353a0f1dSLuo Jie ppe_dev->num_ports = PPE_PORT_MAX; 198353a0f1dSLuo Jie ppe_dev->num_icc_paths = num_icc; 199353a0f1dSLuo Jie 200353a0f1dSLuo Jie ret = ppe_clock_init_and_reset(ppe_dev); 201353a0f1dSLuo Jie if (ret) 202353a0f1dSLuo Jie return dev_err_probe(dev, ret, "PPE clock config failed\n"); 203353a0f1dSLuo Jie 2048a971df9SLuo Jie ret = ppe_hw_config(ppe_dev); 2058a971df9SLuo Jie if (ret) 2068a971df9SLuo Jie return dev_err_probe(dev, ret, "PPE HW config failed\n"); 2078a971df9SLuo Jie 208*a2a7221dSLuo Jie ppe_debugfs_setup(ppe_dev); 209353a0f1dSLuo Jie platform_set_drvdata(pdev, ppe_dev); 210353a0f1dSLuo Jie 211353a0f1dSLuo Jie return 0; 212353a0f1dSLuo Jie } 213353a0f1dSLuo Jie 214*a2a7221dSLuo Jie static void qcom_ppe_remove(struct platform_device *pdev) 215*a2a7221dSLuo Jie { 216*a2a7221dSLuo Jie struct ppe_device *ppe_dev; 217*a2a7221dSLuo Jie 218*a2a7221dSLuo Jie ppe_dev = platform_get_drvdata(pdev); 219*a2a7221dSLuo Jie ppe_debugfs_teardown(ppe_dev); 220*a2a7221dSLuo Jie } 221*a2a7221dSLuo Jie 222353a0f1dSLuo Jie static const struct of_device_id qcom_ppe_of_match[] = { 223353a0f1dSLuo Jie { .compatible = "qcom,ipq9574-ppe" }, 224353a0f1dSLuo Jie {} 225353a0f1dSLuo Jie }; 226353a0f1dSLuo Jie MODULE_DEVICE_TABLE(of, qcom_ppe_of_match); 227353a0f1dSLuo Jie 228353a0f1dSLuo Jie static struct platform_driver qcom_ppe_driver = { 229353a0f1dSLuo Jie .driver = { 230353a0f1dSLuo Jie .name = "qcom_ppe", 231353a0f1dSLuo Jie .of_match_table = qcom_ppe_of_match, 232353a0f1dSLuo Jie }, 233353a0f1dSLuo Jie .probe = qcom_ppe_probe, 234*a2a7221dSLuo Jie .remove = qcom_ppe_remove, 235353a0f1dSLuo Jie }; 236353a0f1dSLuo Jie module_platform_driver(qcom_ppe_driver); 237353a0f1dSLuo Jie 238353a0f1dSLuo Jie MODULE_LICENSE("GPL"); 239353a0f1dSLuo Jie MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPQ PPE driver"); 240