Channagoud Kadabi | 5381ef2 | 2017-02-14 21:34:06 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify |
| 4 | * it under the terms of the GNU General Public License version 2 and |
| 5 | * only version 2 as published by the Free Software Foundation. |
| 6 | * |
| 7 | * This program is distributed in the hope that it will be useful, |
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | * GNU General Public License for more details. |
| 11 | */ |
| 12 | |
| 13 | #include <linux/err.h> |
| 14 | #include <linux/kernel.h> |
| 15 | #include <linux/module.h> |
| 16 | #include <linux/of.h> |
| 17 | #include <linux/of_device.h> |
| 18 | #include <linux/platform_device.h> |
| 19 | #include <linux/mfd/syscon.h> |
| 20 | #include <linux/regmap.h> |
| 21 | |
| 22 | /* Config registers offsets*/ |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 23 | #define DRP_ECC_ERROR_CFG 0x00040000 |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 24 | |
| 25 | /* TRP, DRP interrupt register offsets */ |
| 26 | #define CMN_INTERRUPT_0_ENABLE 0x0003001C |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 27 | #define CMN_INTERRUPT_2_ENABLE 0x0003003C |
| 28 | #define TRP_INTERRUPT_0_ENABLE 0x00020488 |
| 29 | #define DRP_INTERRUPT_ENABLE 0x0004100C |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 30 | |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 31 | #define SB_ERROR_THRESHOLD 0x1 |
| 32 | #define SB_ERROR_THRESHOLD_SHIFT 24 |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 33 | #define SB_DB_TRP_INTERRUPT_ENABLE 0x3 |
| 34 | #define TRP0_INTERRUPT_ENABLE 0x1 |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 35 | #define DRP0_INTERRUPT_ENABLE BIT(6) |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 36 | #define SB_DB_DRP_INTERRUPT_ENABLE 0x3 |
| 37 | |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 38 | static void qcom_llcc_core_setup(struct regmap *llcc_regmap, uint32_t b_off) |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 39 | { |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 40 | u32 sb_err_threshold; |
| 41 | |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 42 | /* Enable TRP in instance 2 of common interrupt enable register */ |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 43 | regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE, |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 44 | TRP0_INTERRUPT_ENABLE, TRP0_INTERRUPT_ENABLE); |
| 45 | |
| 46 | /* Enable ECC interrupts on Tag Ram */ |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 47 | regmap_update_bits(llcc_regmap, b_off + TRP_INTERRUPT_0_ENABLE, |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 48 | SB_DB_TRP_INTERRUPT_ENABLE, SB_DB_TRP_INTERRUPT_ENABLE); |
| 49 | |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 50 | /* Enable SB error for Data RAM */ |
| 51 | sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT); |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 52 | regmap_write(llcc_regmap, b_off + DRP_ECC_ERROR_CFG, sb_err_threshold); |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 53 | |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 54 | /* Enable DRP in instance 2 of common interrupt enable register */ |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 55 | regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE, |
Channagoud Kadabi | dbaf723 | 2016-10-10 15:25:19 -0700 | [diff] [blame] | 56 | DRP0_INTERRUPT_ENABLE, DRP0_INTERRUPT_ENABLE); |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 57 | |
| 58 | /* Enable ECC interrupts on Data Ram */ |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 59 | regmap_write(llcc_regmap, b_off + DRP_INTERRUPT_ENABLE, |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 60 | SB_DB_DRP_INTERRUPT_ENABLE); |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | static int qcom_llcc_core_probe(struct platform_device *pdev) |
| 64 | { |
| 65 | struct regmap *llcc_regmap; |
| 66 | struct device *dev = &pdev->dev; |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 67 | u32 b_off = 0; |
| 68 | int ret = 0; |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 69 | |
| 70 | llcc_regmap = syscon_node_to_regmap(dev->of_node); |
| 71 | |
| 72 | if (IS_ERR(llcc_regmap)) { |
| 73 | dev_err(&pdev->dev, "Cannot find regmap for llcc\n"); |
| 74 | return PTR_ERR(llcc_regmap); |
| 75 | } |
| 76 | |
Channagoud Kadabi | c0a72e7 | 2017-03-27 21:57:09 -0700 | [diff] [blame^] | 77 | ret = of_property_read_u32(dev->of_node, |
| 78 | "qcom,llcc-broadcast-off", &b_off); |
| 79 | if (ret) { |
| 80 | dev_err(&pdev->dev, "Unable to read broadcast-off\n"); |
| 81 | return -EINVAL; |
| 82 | } |
| 83 | |
| 84 | qcom_llcc_core_setup(llcc_regmap, b_off); |
Channagoud Kadabi | 97335b2 | 2016-08-17 13:40:46 -0700 | [diff] [blame] | 85 | |
| 86 | return 0; |
| 87 | } |
| 88 | |
| 89 | static int qcom_llcc_core_remove(struct platform_device *pdev) |
| 90 | { |
| 91 | return 0; |
| 92 | } |
| 93 | |
| 94 | static const struct of_device_id qcom_llcc_core_match_table[] = { |
| 95 | { .compatible = "qcom,llcc-core" }, |
| 96 | { }, |
| 97 | }; |
| 98 | |
| 99 | static struct platform_driver qcom_llcc_core_driver = { |
| 100 | .probe = qcom_llcc_core_probe, |
| 101 | .remove = qcom_llcc_core_remove, |
| 102 | .driver = { |
| 103 | .name = "qcom_llcc_core", |
| 104 | .owner = THIS_MODULE, |
| 105 | .of_match_table = qcom_llcc_core_match_table, |
| 106 | }, |
| 107 | }; |
| 108 | |
| 109 | static int __init qcom_llcc_core_init(void) |
| 110 | { |
| 111 | return platform_driver_register(&qcom_llcc_core_driver); |
| 112 | } |
| 113 | module_init(qcom_llcc_core_init); |
| 114 | |
| 115 | static void __exit qcom_llcc_core_exit(void) |
| 116 | { |
| 117 | platform_driver_unregister(&qcom_llcc_core_driver); |
| 118 | } |
| 119 | module_exit(qcom_llcc_core_exit); |
| 120 | |
| 121 | MODULE_DESCRIPTION("QCOM LLCC Core Driver"); |
| 122 | MODULE_LICENSE("GPL v2"); |