diff options
| author | Osvaldo Banuelos <osvaldob@codeaurora.org> | 2016-03-01 10:38:36 -0800 |
|---|---|---|
| committer | Jeevan Shriram <jshriram@codeaurora.org> | 2016-04-04 19:38:10 -0700 |
| commit | 2bcea99b426ee3cb93f7fec04bcc5a783d19ecb3 (patch) | |
| tree | 209d2ff7fbb5154892c017bf6fe2e610d8ac884b /drivers/clk | |
| parent | ea6575bbdf4cc338a8fd1ad4c87bbca4eb46ade0 (diff) | |
clk: msm: clock-osm: add support for mem-acc level programming
Support an additional column in the OSM look up hardware table
which establishes a mapping between frequency and mem-acc level.
The OSM uses this mapping to program ACC settings which vary
depending upon the performance level. In addition, update the
OSM sequencer and branch instructions to support ACC programming
as part of the clock scaling scheme and define the mem-acc level
associated with each row of the OSM look up tables.
Change-Id: I03e6f189ab0ab6af406a338bd667fb40240d89b3
CRs-Fixed: 981231
Signed-off-by: Osvaldo Banuelos <osvaldob@codeaurora.org>
Diffstat (limited to 'drivers/clk')
| -rw-r--r-- | drivers/clk/msm/clock-osm.c | 216 |
1 files changed, 172 insertions, 44 deletions
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c index 875f8ecd3df1..9fc6cf8d13e2 100644 --- a/drivers/clk/msm/clock-osm.c +++ b/drivers/clk/msm/clock-osm.c @@ -51,10 +51,16 @@ enum clk_osm_lut_data { FREQ, FREQ_DATA, PLL_OVERRIDES, + SPARE_DATA, NUM_FIELDS, }; -#define SEQ_REG(n) (0x300 + n*4) +#define SEQ_REG(n) (0x300 + (n) * 4) +#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n))) +#define MEM_ACC_SEQ_CONST(n) (n) +#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40)) +#define MEM_ACC_SEQ_REG_VAL_START(n) \ + ((n) < 8 ? SEQ_REG(4 + (n)) : SEQ_REG(60 + (n) - 8)) #define OSM_TABLE_SIZE 40 #define MAX_CLUSTER_CNT 2 @@ -65,6 +71,7 @@ enum clk_osm_lut_data { #define FREQ_REG 0x1154 #define VOLT_REG 0x1158 #define OVERRIDE_REG 0x115C +#define SPARE_REG 0x1164 #define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00 #define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04 @@ -153,45 +160,58 @@ enum clk_osm_lut_data { #define MAX_INSTRUCTIONS 256 #define MAX_BR_INSTRUCTIONS 49 +#define MAX_MEM_ACC_LEVELS 4 +#define MAX_MEM_ACC_VAL_PER_LEVEL 3 +#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \ + MAX_MEM_ACC_VAL_PER_LEVEL) +#define MEM_ACC_READ_MASK 0x7 + static u32 seq_instr[] = { 0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491, 0x700a500b, 0x70005001, 0x390938c8, 0xcb44c833, 0xce56cd54, 0x341336e0, 0xadba0000, 0x10004000, 0x70005001, 0x1000500c, 0xc792c5a1, 0x501625e1, 0x3da335a2, 0x50170006, 0x50150006, - 0x1000c633, 0x1000acb3, 0xc422acb4, 0xaefc1000, 0x700a500b, - 0x70005001, 0x5010aefd, 0x5012700b, 0xad41700c, 0x0000adb9, - 0x500c181b, 0x5011500f, 0x181b3413, 0x853984b9, 0x0003bd80, - 0xa0012ba4, 0x71050006, 0x500e1000, 0x500c1000, 0x38801c0a, - 0x1c063b18, 0x1c073b43, 0x1c061000, 0x1c073983, 0x3840500c, - 0x00001c0a, 0x50021000, 0x00007001, 0x81031000, 0x70025003, - 0x70035004, 0x3b441000, 0x81043985, 0x70025003, 0x50054003, - 0xa1467009, 0x0003b1c0, 0x4005238b, 0x83081000, 0x850c848b, - 0x830d1000, 0x850c848e, 0x38811000, 0xa7183842, 0xa79aa759, - 0x0000a7db, 0x8c101000, 0x8d128c91, 0x00008d93, 0x8c141000, - 0x8d168c95, 0x00008d97, 0x50061000, 0x39cd3a4c, 0x3ad03a8f, - 0x10004006, 0x70065007, 0xa00f2c12, 0x00064007, 0x700d7105, - 0xa9641000, 0x40071c1a, 0x1000700d, 0x70065007, 0x50101c16, - 0x24115012, 0x700d4007, 0x10004007, 0xa821a00f, 0x71050006, - 0x700d4007, 0x91ad500c, 0x500f1c15, 0x00005011, 0x2bd41000, - 0xa00f500c, 0x71050006, 0xa00f1000, 0x0006a821, 0x500c7005, - 0x1c1591ad, 0x5011500f, 0x2bce1000, 0x50101c16, 0xa0225012, - 0x0006a82a, 0x91a67105, 0x500f1c15, 0x500c5011, 0xa00f5014, - 0x71050006, 0x10000000, 0x501391a4, 0xa9632217, 0x10001c1a, - 0xa9632217, 0x10001c1a, 0x70075008, 0xa9634008, 0x50091c1a, - 0x40097008, 0x848e1000, 0xb1c0850c, 0x2b990003, 0x1000400d, - 0x1000500d, 0x84b0abaf, 0xbb808531, 0x10000003, 0x0006a037, - 0x10007105, + 0xafb9c633, 0xacb31000, 0xacb41000, 0x1000c422, 0x500baefc, + 0x5001700a, 0xaefd7000, 0x700b5010, 0x700c5012, 0xadb9ad41, + 0x181b0000, 0x500f500c, 0x34135011, 0x84b9181b, 0xbd808539, + 0x2ba40003, 0x0006a001, 0x10007105, 0x1000500e, 0x1c0a500c, + 0x3b181c01, 0x3b431c06, 0x10001c07, 0x39831c06, 0x500c1c07, + 0x1c0a1c02, 0x10000000, 0x70015002, 0x10000000, 0x50038103, + 0x50047002, 0x10007003, 0x39853b44, 0x50038104, 0x40037002, + 0x70095005, 0xb1c0a146, 0x238b0003, 0x10004005, 0x848b8308, + 0x1000850c, 0x848e830d, 0x1000850c, 0x3a4c5006, 0x3a8f39cd, + 0x40063ad0, 0x50071000, 0x2c127006, 0x4007a00f, 0x71050006, + 0x1000700d, 0x1c1aa964, 0x700d4007, 0x50071000, 0x1c167006, + 0x50125010, 0x40072411, 0x4007700d, 0xa00f1000, 0x0006a821, + 0x40077105, 0x500c700d, 0x1c1591ad, 0x5011500f, 0x10000000, + 0x500c2bd4, 0x0006a00f, 0x10007105, 0xa821a00f, 0x70050006, + 0x91ad500c, 0x500f1c15, 0x10005011, 0x1c162bce, 0x50125010, + 0xa82aa022, 0x71050006, 0x1c1591a6, 0x5011500f, 0x5014500c, + 0x0006a00f, 0x00007105, 0x91a41000, 0x22175013, 0x1c1aa963, + 0x22171000, 0x1c1aa963, 0x50081000, 0x40087007, 0x1c1aa963, + 0x70085009, 0x10004009, 0x850c848e, 0x0003b1c0, 0x400d2b99, + 0x500d1000, 0xabaf1000, 0x853184b0, 0x0003bb80, 0xa0371000, + 0x71050006, 0x85481000, 0xbf8084c3, 0x2ba80003, 0xbf8084c2, + 0x2ba70003, 0xbf8084c1, 0x2ba60003, 0x8ec71000, 0xc6dd8dc3, + 0x8c1625ec, 0x8d498c97, 0x8ec61c00, 0xc6dd8dc2, 0x8c1325ec, + 0x8d158c94, 0x8ec51c00, 0xc6dd8dc1, 0x8c1025ec, 0x8d128c91, + 0x8dc01c00, 0x182cc633, 0x84c08548, 0x0003bf80, 0x84c12ba9, + 0x0003bf80, 0x84c22baa, 0x0003bf80, 0x10002bab, 0x8dc08ec4, + 0x25ecc6dd, 0x8c948c13, 0x1c008d15, 0x8dc18ec5, 0x25ecc6dd, + 0x8c978c16, 0x1c008d49, 0x8dc28ec6, 0x25ecc6dd, 0x8ccb8c4a, + 0x1c008d4c, 0xc6338dc3, 0x1000af9b, 0xa759a79a, 0x1000a718, }; static u32 seq_br_instr[] = { - 0xfa, 0x10a, 0x116, 0xce, 0xea, - 0xf2, 0xba, 0xc2, 0x9a, 0xaa, - 0x122, 0xe0, 0x17a, 0x19a, 0x1a2, - 0x130, 0x14c, 0x160, 0x142, 0x96, - 0x186, 0x1cc, 0x1c0, 0x1d4, 0x1e6, - 0x1f4, 0x1f8, 0x30, 0x5e, 0x84, - 0x7a, 0x1fe, 0x34, 0x3c, 0x54, - 0x58, 0x204, 0x2e, + 0x28c, 0x1e6, 0x238, 0xd0, 0xec, + 0xf4, 0xbc, 0xc4, 0x9c, 0xac, + 0xfc, 0xe2, 0x154, 0x174, 0x17c, + 0x10a, 0x126, 0x13a, 0x11c, 0x98, + 0x160, 0x1a6, 0x19a, 0x1ae, 0x1c0, + 0x1ce, 0x1d2, 0x30, 0x60, 0x86, + 0x7c, 0x1d8, 0x34, 0x3c, 0x56, + 0x5a, 0x1de, 0x2e, 0x222, 0x212, + 0x202, 0x254, 0x264, 0x274, 0x288, }; DEFINE_EXT_CLK(xo_ao, NULL); @@ -202,6 +222,7 @@ struct osm_entry { u16 open_loop_volt; u32 freq_data; u32 override_data; + u32 spare_data; long frequency; }; @@ -230,10 +251,13 @@ struct clk_osm { u32 apcs_cfg_rcgr; u32 apcs_cmd_rcgr; u32 apcs_pll_user_ctl; + u32 apcs_mem_acc_cfg[MAX_MEM_ACC_VAL_PER_LEVEL]; + u32 apcs_mem_acc_val[MAX_MEM_ACC_VALUES]; u32 apm_mode_ctl; u32 apm_ctrl_status; u32 osm_clk_rate; u32 xo_clk_rate; + bool secure_init; bool red_fsm_en; bool boost_fsm_en; bool safe_fsm_en; @@ -396,20 +420,21 @@ static void clk_osm_print_osm_table(struct clk_osm *c) struct osm_entry *table = c->osm_table; u32 pll_src, pll_div, lval; - pr_debug("Index, Frequency, VC, OLV (mv), PLLSrc, PLLDivVal, LVal\n"); + pr_debug("Index, Frequency, VC, OLV (mv), PLL Src, PLL Div, L-Val, ACC Level\n"); for (i = 0; i < c->num_entries; i++) { pll_src = (table[i].freq_data & GENMASK(27, 26)) >> 26; pll_div = (table[i].freq_data & GENMASK(25, 24)) >> 24; lval = table[i].freq_data & GENMASK(7, 0); - pr_debug("%3d, %11lu, %2u, %5u, %6u, %8u, %7u\n", + pr_debug("%3d, %11lu, %2u, %5u, %6u, %8u, %7u, %5u\n", i, table[i].frequency, table[i].virtual_corner, table[i].open_loop_volt, pll_src, pll_div, - lval); + lval, + table[i].spare_data); } pr_debug("APM crossover corner: %d\n", c->apm_crossover_vc); @@ -466,10 +491,12 @@ static int clk_osm_get_lut(struct platform_device *pdev, c->osm_table[j].frequency = array[i + FREQ]; c->osm_table[j].freq_data = array[i + FREQ_DATA]; c->osm_table[j].override_data = array[i + PLL_OVERRIDES]; - pr_debug("index=%d freq=%ld freq_data=0x%x override_data=0x%x\n", + c->osm_table[j].spare_data = array[i + SPARE_DATA]; + pr_debug("index=%d freq=%ld freq_data=0x%x override_data=0x%x spare_data=0x%x\n", j, c->osm_table[j].frequency, c->osm_table[j].freq_data, - c->osm_table[j].override_data); + c->osm_table[j].override_data, + c->osm_table[j].spare_data); data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16; if (!last_entry && data == MAX_CONFIG) { @@ -641,6 +668,49 @@ static int clk_osm_parse_dt_configs(struct platform_device *pdev) of_property_read_bool(of, "qcom,pc-fsm-en"); devm_kfree(&pdev->dev, array); + + perfcl_clk.secure_init = pwrcl_clk.secure_init = + of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz"); + + if (!pwrcl_clk.secure_init) + return rc; + + rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-cfg", + pwrcl_clk.apcs_mem_acc_cfg, + MAX_MEM_ACC_VAL_PER_LEVEL); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-cfg property, rc=%d\n", + rc); + return -EINVAL; + } + + of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-cfg", + perfcl_clk.apcs_mem_acc_cfg, + MAX_MEM_ACC_VAL_PER_LEVEL); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-cfg property, rc=%d\n", + rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-val", + pwrcl_clk.apcs_mem_acc_val, + MAX_MEM_ACC_VALUES); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-val property, rc=%d\n", + rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-val", + perfcl_clk.apcs_mem_acc_val, + MAX_MEM_ACC_VALUES); + if (rc) { + dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-val property, rc=%d\n", + rc); + return -EINVAL; + } + return rc; } @@ -793,12 +863,12 @@ static void clk_osm_setup_cluster_pll(struct clk_osm *c) writel_relaxed(0x7, c->vbases[PLL_BASE] + PLL_MODE); } -static void clk_osm_setup_hw_table(struct clk_osm *c) +static int clk_osm_setup_hw_table(struct clk_osm *c) { struct osm_entry *entry = c->osm_table; int i; - u32 freq_val, volt_val, override_val; - u32 table_entry_offset; + u32 freq_val, volt_val, override_val, spare_val; + u32 table_entry_offset, last_spare, last_virtual_corner = 0; for (i = 0; i < OSM_TABLE_SIZE; i++) { if (i < c->num_entries) { @@ -806,17 +876,34 @@ static void clk_osm_setup_hw_table(struct clk_osm *c) volt_val = BVAL(21, 16, entry[i].virtual_corner) | BVAL(11, 0, entry[i].open_loop_volt); override_val = entry[i].override_data; + spare_val = entry[i].spare_data; + + if (last_virtual_corner && last_virtual_corner == + entry[i].virtual_corner && last_spare != + entry[i].spare_data) { + pr_err("invalid LUT entry at row=%d virtual_corner=%d, spare_data=%d\n", + i, entry[i].virtual_corner, + entry[i].spare_data); + return -EINVAL; + } + last_virtual_corner = entry[i].virtual_corner; + last_spare = entry[i].spare_data; } + table_entry_offset = i * OSM_REG_SIZE; clk_osm_write_reg(c, i, INDEX_REG + table_entry_offset); clk_osm_write_reg(c, freq_val, FREQ_REG + table_entry_offset); clk_osm_write_reg(c, volt_val, VOLT_REG + table_entry_offset); clk_osm_write_reg(c, override_val, OVERRIDE_REG + table_entry_offset); + clk_osm_write_reg(c, spare_val, SPARE_REG + + table_entry_offset); } /* Make sure all writes go through */ mb(); + + return 0; } static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c) @@ -1207,6 +1294,36 @@ static void clk_osm_program_apm_regs(struct clk_osm *c) clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(26)); } +static void clk_osm_program_mem_acc_regs(struct clk_osm *c) +{ + int i; + + if (!c->secure_init) + return; + + clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(50) + + c->cluster_num * OSM_CORE_TABLE_SIZE, + SEQ_REG(49)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(50)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53)); + clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54)); + clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(0), SEQ_REG(55)); + clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(1), SEQ_REG(56)); + clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(2), SEQ_REG(57)); + clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(3), SEQ_REG(58)); + clk_osm_write_reg(c, MEM_ACC_READ_MASK, SEQ_REG(59)); + + for (i = 0; i < MAX_MEM_ACC_VALUES; i++) + clk_osm_write_reg(c, c->apcs_mem_acc_val[i], + MEM_ACC_SEQ_REG_VAL_START(i)); + + for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++) + clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i], + MEM_ACC_SEQ_REG_CFG_START(i)); +} + void clk_osm_setup_sequencer(struct clk_osm *c) { u32 i; @@ -1267,7 +1384,7 @@ static void clk_osm_do_additional_setup(struct clk_osm *c, { u32 val; - if (!of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz")) + if (!c->secure_init) return; dev_info(&pdev->dev, "Performing additional OSM setup due to lack of TZ for cluster=%d\n", @@ -1287,6 +1404,9 @@ static void clk_osm_do_additional_setup(struct clk_osm *c, /* APM Programming */ clk_osm_program_apm_regs(c); + /* MEM-ACC Programming */ + clk_osm_program_mem_acc_regs(c); + /* GFMUX Programming */ clk_osm_write_reg(c, c->apcs_cfg_rcgr, SEQ_REG(16)); clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17)); @@ -1789,8 +1909,16 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) clk_osm_write_reg(&pwrcl_clk, PLL_MIN_LVAL, SEQ_REG(27)); clk_osm_write_reg(&perfcl_clk, PLL_MIN_LVAL, SEQ_REG(27)); - clk_osm_setup_hw_table(&pwrcl_clk); - clk_osm_setup_hw_table(&perfcl_clk); + rc = clk_osm_setup_hw_table(&pwrcl_clk); + if (rc) { + dev_err(&pdev->dev, "failed to setup power cluster hardware table\n"); + goto exit; + } + rc = clk_osm_setup_hw_table(&perfcl_clk); + if (rc) { + dev_err(&pdev->dev, "failed to setup perf cluster hardware table\n"); + goto exit; + } /* Policy tuning */ rc = clk_osm_set_cc_policy(pdev); @@ -1895,7 +2023,7 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev) return 0; exit: - dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d", + dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n", rc); panic("Unable to Setup OSM"); } |
