1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534 |
- /* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #define pr_fmt(fmt) "ACC: %s: " fmt, __func__
- #include <linux/module.h>
- #include <linux/mutex.h>
- #include <linux/types.h>
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <linux/err.h>
- #include <linux/of.h>
- #include <linux/of_device.h>
- #include <linux/io.h>
- #include <linux/platform_device.h>
- #include <linux/regulator/driver.h>
- #include <linux/regulator/machine.h>
- #include <linux/regulator/of_regulator.h>
- #include <linux/string.h>
- #include <soc/qcom/scm.h>
- #define MEM_ACC_DEFAULT_SEL_SIZE 2
- #define BYTES_PER_FUSE_ROW 8
- /* mem-acc config flags */
- enum {
- MEM_ACC_USE_CORNER_ACC_MAP = BIT(0),
- MEM_ACC_USE_ADDR_VAL_MAP = BIT(1),
- };
- #define FUSE_MAP_NO_MATCH (-1)
- #define FUSE_PARAM_MATCH_ANY (-1)
- #define PARAM_MATCH_ANY (-1)
- enum {
- MEMORY_L1,
- MEMORY_L2,
- MEMORY_MAX,
- };
- #define MEM_ACC_TYPE_MAX 6
- /**
- * struct acc_reg_value - Acc register configuration structure
- * @addr_index: An index in to phys_reg_addr_list and remap_reg_addr_list
- * to get the ACC register physical address and remapped address.
- * @reg_val: Value to program in to the register mapped by addr_index.
- */
- struct acc_reg_value {
- u32 addr_index;
- u32 reg_val;
- };
- struct corner_acc_reg_config {
- struct acc_reg_value *reg_config_list;
- int max_reg_config_len;
- };
- struct mem_acc_regulator {
- struct device *dev;
- struct regulator_desc rdesc;
- struct regulator_dev *rdev;
- int corner;
- bool mem_acc_supported[MEMORY_MAX];
- bool mem_acc_custom_supported[MEMORY_MAX];
- u32 *acc_sel_mask[MEMORY_MAX];
- u32 *acc_sel_bit_pos[MEMORY_MAX];
- u32 acc_sel_bit_size[MEMORY_MAX];
- u32 num_acc_sel[MEMORY_MAX];
- u32 *acc_en_bit_pos;
- u32 num_acc_en;
- u32 *corner_acc_map;
- u32 num_corners;
- u32 override_fuse_value;
- int override_map_match;
- int override_map_count;
- void __iomem *acc_sel_base[MEMORY_MAX];
- void __iomem *acc_en_base;
- phys_addr_t acc_sel_addr[MEMORY_MAX];
- phys_addr_t acc_en_addr;
- u32 flags;
- void __iomem *acc_custom_addr[MEMORY_MAX];
- u32 *acc_custom_data[MEMORY_MAX];
- phys_addr_t mem_acc_type_addr[MEM_ACC_TYPE_MAX];
- u32 *mem_acc_type_data;
- /* eFuse parameters */
- phys_addr_t efuse_addr;
- void __iomem *efuse_base;
- u32 num_acc_reg;
- u32 *phys_reg_addr_list;
- void __iomem **remap_reg_addr_list;
- struct corner_acc_reg_config *corner_acc_reg_config;
- u32 *override_acc_range_fuse_list;
- int override_acc_range_fuse_num;
- };
- static DEFINE_MUTEX(mem_acc_memory_mutex);
- static u64 mem_acc_read_efuse_row(struct mem_acc_regulator *mem_acc_vreg,
- u32 row_num, bool use_tz_api)
- {
- int rc;
- u64 efuse_bits;
- struct scm_desc desc = {0};
- struct mem_acc_read_req {
- u32 row_address;
- int addr_type;
- } req;
- struct mem_acc_read_rsp {
- u32 row_data[2];
- u32 status;
- } rsp;
- if (!use_tz_api) {
- efuse_bits = readq_relaxed(mem_acc_vreg->efuse_base
- + row_num * BYTES_PER_FUSE_ROW);
- return efuse_bits;
- }
- desc.args[0] = req.row_address = mem_acc_vreg->efuse_addr +
- row_num * BYTES_PER_FUSE_ROW;
- desc.args[1] = req.addr_type = 0;
- desc.arginfo = SCM_ARGS(2);
- efuse_bits = 0;
- if (!is_scm_armv8()) {
- rc = scm_call(SCM_SVC_FUSE, SCM_FUSE_READ,
- &req, sizeof(req), &rsp, sizeof(rsp));
- } else {
- rc = scm_call2(SCM_SIP_FNID(SCM_SVC_FUSE, SCM_FUSE_READ),
- &desc);
- rsp.row_data[0] = desc.ret[0];
- rsp.row_data[1] = desc.ret[1];
- rsp.status = desc.ret[2];
- }
- if (rc) {
- pr_err("read row %d failed, err code = %d", row_num, rc);
- } else {
- efuse_bits = ((u64)(rsp.row_data[1]) << 32) +
- (u64)rsp.row_data[0];
- }
- return efuse_bits;
- }
- static inline u32 apc_to_acc_corner(struct mem_acc_regulator *mem_acc_vreg,
- int corner)
- {
- /*
- * corner_acc_map maps the corner from index 0 and APC corner value
- * starts from the value 1
- */
- return mem_acc_vreg->corner_acc_map[corner - 1];
- }
- static void __update_acc_sel(struct mem_acc_regulator *mem_acc_vreg,
- int corner, int mem_type)
- {
- u32 acc_data, acc_data_old, i, bit, acc_corner;
- acc_data = readl_relaxed(mem_acc_vreg->acc_sel_base[mem_type]);
- acc_data_old = acc_data;
- for (i = 0; i < mem_acc_vreg->num_acc_sel[mem_type]; i++) {
- bit = mem_acc_vreg->acc_sel_bit_pos[mem_type][i];
- acc_data &= ~mem_acc_vreg->acc_sel_mask[mem_type][i];
- acc_corner = apc_to_acc_corner(mem_acc_vreg, corner);
- acc_data |= (acc_corner << bit) &
- mem_acc_vreg->acc_sel_mask[mem_type][i];
- }
- pr_debug("corner=%d old_acc_sel=0x%02x new_acc_sel=0x%02x mem_type=%d\n",
- corner, acc_data_old, acc_data, mem_type);
- writel_relaxed(acc_data, mem_acc_vreg->acc_sel_base[mem_type]);
- }
- static void __update_acc_type(struct mem_acc_regulator *mem_acc_vreg,
- int corner)
- {
- int i, rc;
- for (i = 0; i < MEM_ACC_TYPE_MAX; i++) {
- if (mem_acc_vreg->mem_acc_type_addr[i]) {
- rc = scm_io_write(mem_acc_vreg->mem_acc_type_addr[i],
- mem_acc_vreg->mem_acc_type_data[corner - 1 + i *
- mem_acc_vreg->num_corners]);
- if (rc)
- pr_err("scm_io_write: %pa failure rc:%d\n",
- &(mem_acc_vreg->mem_acc_type_addr[i]),
- rc);
- }
- }
- }
- static void __update_acc_custom(struct mem_acc_regulator *mem_acc_vreg,
- int corner, int mem_type)
- {
- writel_relaxed(
- mem_acc_vreg->acc_custom_data[mem_type][corner-1],
- mem_acc_vreg->acc_custom_addr[mem_type]);
- pr_debug("corner=%d mem_type=%d custom_data=0x%2x\n", corner,
- mem_type, mem_acc_vreg->acc_custom_data[mem_type][corner-1]);
- }
- static void update_acc_sel(struct mem_acc_regulator *mem_acc_vreg, int corner)
- {
- int i;
- for (i = 0; i < MEMORY_MAX; i++) {
- if (mem_acc_vreg->mem_acc_supported[i])
- __update_acc_sel(mem_acc_vreg, corner, i);
- if (mem_acc_vreg->mem_acc_custom_supported[i])
- __update_acc_custom(mem_acc_vreg, corner, i);
- }
- if (mem_acc_vreg->mem_acc_type_data)
- __update_acc_type(mem_acc_vreg, corner);
- }
- static void update_acc_reg(struct mem_acc_regulator *mem_acc_vreg, int corner)
- {
- struct corner_acc_reg_config *corner_acc_reg_config;
- struct acc_reg_value *reg_config_list;
- int i, index;
- u32 addr_index, reg_val;
- corner_acc_reg_config =
- &mem_acc_vreg->corner_acc_reg_config[mem_acc_vreg->corner];
- reg_config_list = corner_acc_reg_config->reg_config_list;
- for (i = 0; i < corner_acc_reg_config->max_reg_config_len; i++) {
- /*
- * Use (corner - 1) in the below equation as
- * the reg_config_list[] stores the values starting from
- * index '0' where as the minimum corner value allowed
- * in regulator framework is '1'.
- */
- index = (corner - 1) * corner_acc_reg_config->max_reg_config_len
- + i;
- addr_index = reg_config_list[index].addr_index;
- reg_val = reg_config_list[index].reg_val;
- if (addr_index == PARAM_MATCH_ANY)
- break;
- writel_relaxed(reg_val,
- mem_acc_vreg->remap_reg_addr_list[addr_index]);
- /* make sure write complete */
- mb();
- pr_debug("corner=%d register:0x%x value:0x%x\n", corner,
- mem_acc_vreg->phys_reg_addr_list[addr_index], reg_val);
- }
- }
- static int mem_acc_regulator_set_voltage(struct regulator_dev *rdev,
- int corner, int corner_max, unsigned int *selector)
- {
- struct mem_acc_regulator *mem_acc_vreg = rdev_get_drvdata(rdev);
- int i;
- if (corner > mem_acc_vreg->num_corners) {
- pr_err("Invalid corner=%d requested\n", corner);
- return -EINVAL;
- }
- pr_debug("old corner=%d, new corner=%d\n",
- mem_acc_vreg->corner, corner);
- if (corner == mem_acc_vreg->corner)
- return 0;
- /* go up or down one level at a time */
- mutex_lock(&mem_acc_memory_mutex);
- if (mem_acc_vreg->flags & MEM_ACC_USE_ADDR_VAL_MAP) {
- update_acc_reg(mem_acc_vreg, corner);
- } else if (mem_acc_vreg->flags & MEM_ACC_USE_CORNER_ACC_MAP) {
- if (corner > mem_acc_vreg->corner) {
- for (i = mem_acc_vreg->corner + 1; i <= corner; i++) {
- pr_debug("UP: to corner %d\n", i);
- update_acc_sel(mem_acc_vreg, i);
- }
- } else {
- for (i = mem_acc_vreg->corner - 1; i >= corner; i--) {
- pr_debug("DOWN: to corner %d\n", i);
- update_acc_sel(mem_acc_vreg, i);
- }
- }
- }
- mutex_unlock(&mem_acc_memory_mutex);
- pr_debug("new voltage corner set %d\n", corner);
- mem_acc_vreg->corner = corner;
- return 0;
- }
- static int mem_acc_regulator_get_voltage(struct regulator_dev *rdev)
- {
- struct mem_acc_regulator *mem_acc_vreg = rdev_get_drvdata(rdev);
- return mem_acc_vreg->corner;
- }
- static struct regulator_ops mem_acc_corner_ops = {
- .set_voltage = mem_acc_regulator_set_voltage,
- .get_voltage = mem_acc_regulator_get_voltage,
- };
- static int __mem_acc_sel_init(struct mem_acc_regulator *mem_acc_vreg,
- int mem_type)
- {
- int i;
- u32 bit, mask;
- mem_acc_vreg->acc_sel_mask[mem_type] = devm_kzalloc(mem_acc_vreg->dev,
- mem_acc_vreg->num_acc_sel[mem_type] * sizeof(u32), GFP_KERNEL);
- if (!mem_acc_vreg->acc_sel_mask[mem_type])
- return -ENOMEM;
- for (i = 0; i < mem_acc_vreg->num_acc_sel[mem_type]; i++) {
- bit = mem_acc_vreg->acc_sel_bit_pos[mem_type][i];
- mask = BIT(mem_acc_vreg->acc_sel_bit_size[mem_type]) - 1;
- mem_acc_vreg->acc_sel_mask[mem_type][i] = mask << bit;
- }
- return 0;
- }
- static int mem_acc_sel_init(struct mem_acc_regulator *mem_acc_vreg)
- {
- int i, rc;
- for (i = 0; i < MEMORY_MAX; i++) {
- if (mem_acc_vreg->mem_acc_supported[i]) {
- rc = __mem_acc_sel_init(mem_acc_vreg, i);
- if (rc) {
- pr_err("Unable to initialize mem_type=%d rc=%d\n",
- i, rc);
- return rc;
- }
- }
- }
- return 0;
- }
- static void mem_acc_en_init(struct mem_acc_regulator *mem_acc_vreg)
- {
- int i, bit;
- u32 acc_data;
- acc_data = readl_relaxed(mem_acc_vreg->acc_en_base);
- pr_debug("init: acc_en_register=%x\n", acc_data);
- for (i = 0; i < mem_acc_vreg->num_acc_en; i++) {
- bit = mem_acc_vreg->acc_en_bit_pos[i];
- acc_data |= BIT(bit);
- }
- pr_debug("final: acc_en_register=%x\n", acc_data);
- writel_relaxed(acc_data, mem_acc_vreg->acc_en_base);
- }
- static int populate_acc_data(struct mem_acc_regulator *mem_acc_vreg,
- const char *prop_name, u32 **value, u32 *len)
- {
- int rc;
- if (!of_get_property(mem_acc_vreg->dev->of_node, prop_name, len)) {
- pr_err("Unable to find %s property\n", prop_name);
- return -EINVAL;
- }
- *len /= sizeof(u32);
- if (!(*len)) {
- pr_err("Incorrect entries in %s\n", prop_name);
- return -EINVAL;
- }
- *value = devm_kzalloc(mem_acc_vreg->dev, (*len) * sizeof(u32),
- GFP_KERNEL);
- if (!(*value)) {
- pr_err("Unable to allocate memory for %s\n", prop_name);
- return -ENOMEM;
- }
- pr_debug("Found %s, data-length = %d\n", prop_name, *len);
- rc = of_property_read_u32_array(mem_acc_vreg->dev->of_node,
- prop_name, *value, *len);
- if (rc) {
- pr_err("Unable to populate %s rc=%d\n", prop_name, rc);
- return rc;
- }
- return 0;
- }
- static int mem_acc_sel_setup(struct mem_acc_regulator *mem_acc_vreg,
- struct resource *res, int mem_type)
- {
- int len, rc;
- char *mem_select_str;
- char *mem_select_size_str;
- mem_acc_vreg->acc_sel_addr[mem_type] = res->start;
- len = res->end - res->start + 1;
- pr_debug("'acc_sel_addr' = %pa mem_type=%d (len=%d)\n",
- &res->start, mem_type, len);
- mem_acc_vreg->acc_sel_base[mem_type] = devm_ioremap(mem_acc_vreg->dev,
- mem_acc_vreg->acc_sel_addr[mem_type], len);
- if (!mem_acc_vreg->acc_sel_base[mem_type]) {
- pr_err("Unable to map 'acc_sel_addr' %pa for mem_type=%d\n",
- &mem_acc_vreg->acc_sel_addr[mem_type], mem_type);
- return -EINVAL;
- }
- switch (mem_type) {
- case MEMORY_L1:
- mem_select_str = "qcom,acc-sel-l1-bit-pos";
- mem_select_size_str = "qcom,acc-sel-l1-bit-size";
- break;
- case MEMORY_L2:
- mem_select_str = "qcom,acc-sel-l2-bit-pos";
- mem_select_size_str = "qcom,acc-sel-l2-bit-size";
- break;
- default:
- pr_err("Invalid memory type: %d\n", mem_type);
- return -EINVAL;
- }
- mem_acc_vreg->acc_sel_bit_size[mem_type] = MEM_ACC_DEFAULT_SEL_SIZE;
- of_property_read_u32(mem_acc_vreg->dev->of_node, mem_select_size_str,
- &mem_acc_vreg->acc_sel_bit_size[mem_type]);
- rc = populate_acc_data(mem_acc_vreg, mem_select_str,
- &mem_acc_vreg->acc_sel_bit_pos[mem_type],
- &mem_acc_vreg->num_acc_sel[mem_type]);
- if (rc)
- pr_err("Unable to populate '%s' rc=%d\n", mem_select_str, rc);
- return rc;
- }
- static int mem_acc_efuse_init(struct platform_device *pdev,
- struct mem_acc_regulator *mem_acc_vreg)
- {
- struct resource *res;
- int len;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse_addr");
- if (!res || !res->start) {
- mem_acc_vreg->efuse_base = NULL;
- pr_debug("'efuse_addr' resource missing or not used.\n");
- return 0;
- }
- mem_acc_vreg->efuse_addr = res->start;
- len = res->end - res->start + 1;
- pr_info("efuse_addr = %pa (len=0x%x)\n", &res->start, len);
- mem_acc_vreg->efuse_base = devm_ioremap(&pdev->dev,
- mem_acc_vreg->efuse_addr, len);
- if (!mem_acc_vreg->efuse_base) {
- pr_err("Unable to map efuse_addr %pa\n",
- &mem_acc_vreg->efuse_addr);
- return -EINVAL;
- }
- return 0;
- }
- static int mem_acc_custom_data_init(struct platform_device *pdev,
- struct mem_acc_regulator *mem_acc_vreg,
- int mem_type)
- {
- struct resource *res;
- char *custom_apc_addr_str, *custom_apc_data_str;
- int len, rc = 0;
- switch (mem_type) {
- case MEMORY_L1:
- custom_apc_addr_str = "acc-l1-custom";
- custom_apc_data_str = "qcom,l1-acc-custom-data";
- break;
- case MEMORY_L2:
- custom_apc_addr_str = "acc-l2-custom";
- custom_apc_data_str = "qcom,l2-acc-custom-data";
- break;
- default:
- pr_err("Invalid memory type: %d\n", mem_type);
- return -EINVAL;
- }
- if (!of_find_property(mem_acc_vreg->dev->of_node,
- custom_apc_data_str, NULL)) {
- pr_debug("%s custom_data not specified\n", custom_apc_data_str);
- return 0;
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- custom_apc_addr_str);
- if (!res || !res->start) {
- pr_debug("%s resource missing\n", custom_apc_addr_str);
- return -EINVAL;
- }
- len = res->end - res->start + 1;
- mem_acc_vreg->acc_custom_addr[mem_type] =
- devm_ioremap(mem_acc_vreg->dev, res->start, len);
- if (!mem_acc_vreg->acc_custom_addr[mem_type]) {
- pr_err("Unable to map %s %pa\n",
- custom_apc_addr_str, &res->start);
- return -EINVAL;
- }
- rc = populate_acc_data(mem_acc_vreg, custom_apc_data_str,
- &mem_acc_vreg->acc_custom_data[mem_type], &len);
- if (rc) {
- pr_err("Unable to find %s rc=%d\n", custom_apc_data_str, rc);
- return rc;
- }
- if (mem_acc_vreg->num_corners != len) {
- pr_err("Custom data is not present for all the corners\n");
- return -EINVAL;
- }
- mem_acc_vreg->mem_acc_custom_supported[mem_type] = true;
- return 0;
- }
- static int override_mem_acc_custom_data(struct mem_acc_regulator *mem_acc_vreg,
- int mem_type)
- {
- char *custom_apc_data_str;
- int len, rc = 0, i;
- int tuple_count, tuple_match;
- u32 index = 0, value = 0;
- switch (mem_type) {
- case MEMORY_L1:
- custom_apc_data_str = "qcom,override-l1-acc-custom-data";
- break;
- case MEMORY_L2:
- custom_apc_data_str = "qcom,override-l2-acc-custom-data";
- break;
- default:
- pr_err("Invalid memory type: %d\n", mem_type);
- return -EINVAL;
- }
- if (!of_find_property(mem_acc_vreg->dev->of_node,
- custom_apc_data_str, &len)) {
- pr_debug("%s not specified\n", custom_apc_data_str);
- return 0;
- }
- if (mem_acc_vreg->override_map_count) {
- if (mem_acc_vreg->override_map_match == FUSE_MAP_NO_MATCH)
- return 0;
- tuple_count = mem_acc_vreg->override_map_count;
- tuple_match = mem_acc_vreg->override_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != mem_acc_vreg->num_corners * tuple_count * sizeof(u32)) {
- pr_err("%s length=%d is invalid\n", custom_apc_data_str, len);
- return -EINVAL;
- }
- for (i = 0; i < mem_acc_vreg->num_corners; i++) {
- index = (tuple_match * mem_acc_vreg->num_corners) + i;
- rc = of_property_read_u32_index(mem_acc_vreg->dev->of_node,
- custom_apc_data_str, index, &value);
- if (rc) {
- pr_err("Unable read %s index %u, rc=%d\n",
- custom_apc_data_str, index, rc);
- return rc;
- }
- mem_acc_vreg->acc_custom_data[mem_type][i] = value;
- }
- return 0;
- }
- static int mem_acc_override_corner_map(struct mem_acc_regulator *mem_acc_vreg)
- {
- int len = 0, i, rc;
- int tuple_count, tuple_match;
- u32 index = 0, value = 0;
- char *prop_str = "qcom,override-corner-acc-map";
- if (!of_find_property(mem_acc_vreg->dev->of_node, prop_str, &len))
- return 0;
- if (mem_acc_vreg->override_map_count) {
- if (mem_acc_vreg->override_map_match == FUSE_MAP_NO_MATCH)
- return 0;
- tuple_count = mem_acc_vreg->override_map_count;
- tuple_match = mem_acc_vreg->override_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != mem_acc_vreg->num_corners * tuple_count * sizeof(u32)) {
- pr_err("%s length=%d is invalid\n", prop_str, len);
- return -EINVAL;
- }
- for (i = 0; i < mem_acc_vreg->num_corners; i++) {
- index = (tuple_match * mem_acc_vreg->num_corners) + i;
- rc = of_property_read_u32_index(mem_acc_vreg->dev->of_node,
- prop_str, index, &value);
- if (rc) {
- pr_err("Unable read %s index %u, rc=%d\n",
- prop_str, index, rc);
- return rc;
- }
- mem_acc_vreg->corner_acc_map[i] = value;
- }
- return 0;
- }
- static void mem_acc_read_efuse_param(struct mem_acc_regulator *mem_acc_vreg,
- u32 *fuse_sel, int *val)
- {
- u64 fuse_bits;
- fuse_bits = mem_acc_read_efuse_row(mem_acc_vreg, fuse_sel[0],
- fuse_sel[3]);
- /*
- * fuse_sel[1] = LSB position in row (shift)
- * fuse_sel[2] = num of bits (mask)
- */
- *val = (fuse_bits >> fuse_sel[1]) & ((1 << fuse_sel[2]) - 1);
- }
- #define FUSE_TUPLE_SIZE 4
- static int mem_acc_parse_override_fuse_version_map(
- struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = mem_acc_vreg->dev->of_node;
- int i, rc, tuple_size;
- int len = 0;
- u32 *tmp;
- u32 fuse_sel[4];
- char *prop_str;
- prop_str = "qcom,override-acc-fuse-sel";
- rc = of_property_read_u32_array(of_node, prop_str, fuse_sel,
- FUSE_TUPLE_SIZE);
- if (rc < 0) {
- pr_err("Read failed - %s rc=%d\n", prop_str, rc);
- return rc;
- }
- mem_acc_read_efuse_param(mem_acc_vreg, fuse_sel,
- &mem_acc_vreg->override_fuse_value);
- prop_str = "qcom,override-fuse-version-map";
- if (!of_find_property(of_node, prop_str, &len))
- return -EINVAL;
- tuple_size = 1;
- mem_acc_vreg->override_map_count = len / (sizeof(u32) * tuple_size);
- if (len == 0 || len % (sizeof(u32) * tuple_size)) {
- pr_err("%s length=%d is invalid\n", prop_str, len);
- return -EINVAL;
- }
- tmp = kzalloc(len, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
- rc = of_property_read_u32_array(of_node, prop_str, tmp,
- mem_acc_vreg->override_map_count * tuple_size);
- if (rc) {
- pr_err("could not read %s rc=%d\n", prop_str, rc);
- goto done;
- }
- for (i = 0; i < mem_acc_vreg->override_map_count; i++) {
- if (tmp[i * tuple_size] != mem_acc_vreg->override_fuse_value
- && tmp[i * tuple_size] != FUSE_PARAM_MATCH_ANY) {
- continue;
- } else {
- mem_acc_vreg->override_map_match = i;
- break;
- }
- }
- if (mem_acc_vreg->override_map_match != FUSE_MAP_NO_MATCH)
- pr_info("override_fuse_val=%d, %s tuple match found: %d\n",
- mem_acc_vreg->override_fuse_value, prop_str,
- mem_acc_vreg->override_map_match);
- else
- pr_err("%s tuple match not found\n", prop_str);
- done:
- kfree(tmp);
- return rc;
- }
- static int mem_acc_parse_override_fuse_version_range(
- struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = mem_acc_vreg->dev->of_node;
- int i, j, rc, size, row_size;
- int num_fuse_sel, len = 0;
- u32 *tmp = NULL;
- char *prop_str;
- u32 *fuse_val, *fuse_sel;
- char *buf = NULL;
- int pos = 0, buflen;
- prop_str = "qcom,override-acc-range-fuse-list";
- if (!of_find_property(of_node, prop_str, &len)) {
- pr_err("%s property is missing\n", prop_str);
- return -EINVAL;
- }
- size = len / sizeof(u32);
- if (len == 0 || (size % FUSE_TUPLE_SIZE)) {
- pr_err("%s property length (%d) is invalid\n", prop_str, len);
- return -EINVAL;
- }
- num_fuse_sel = size / FUSE_TUPLE_SIZE;
- fuse_val = devm_kcalloc(mem_acc_vreg->dev, num_fuse_sel,
- sizeof(*fuse_val), GFP_KERNEL);
- if (!fuse_val)
- return -ENOMEM;
- mem_acc_vreg->override_acc_range_fuse_list = fuse_val;
- mem_acc_vreg->override_acc_range_fuse_num = num_fuse_sel;
- fuse_sel = kzalloc(len, GFP_KERNEL);
- if (!fuse_sel) {
- rc = -ENOMEM;
- goto done;
- }
- rc = of_property_read_u32_array(of_node, prop_str, fuse_sel,
- size);
- if (rc) {
- pr_err("%s read failed, rc=%d\n", prop_str, rc);
- goto done;
- }
- for (i = 0; i < num_fuse_sel; i++) {
- mem_acc_read_efuse_param(mem_acc_vreg, &fuse_sel[i * 4],
- &fuse_val[i]);
- }
- prop_str = "qcom,override-fuse-range-map";
- if (!of_find_property(of_node, prop_str, &len))
- goto done;
- row_size = num_fuse_sel * 2;
- mem_acc_vreg->override_map_count = len / (sizeof(u32) * row_size);
- if (len == 0 || len % (sizeof(u32) * row_size)) {
- pr_err("%s length=%d is invalid\n", prop_str, len);
- rc = -EINVAL;
- goto done;
- }
- tmp = kzalloc(len, GFP_KERNEL);
- if (!tmp) {
- rc = -ENOMEM;
- goto done;
- }
- rc = of_property_read_u32_array(of_node, prop_str, tmp,
- mem_acc_vreg->override_map_count * row_size);
- if (rc) {
- pr_err("could not read %s rc=%d\n", prop_str, rc);
- goto done;
- }
- for (i = 0; i < mem_acc_vreg->override_map_count; i++) {
- for (j = 0; j < num_fuse_sel; j++) {
- if (tmp[i * row_size + j * 2] > fuse_val[j]
- || tmp[i * row_size + j * 2 + 1] < fuse_val[j])
- break;
- }
- if (j == num_fuse_sel) {
- mem_acc_vreg->override_map_match = i;
- break;
- }
- }
- /*
- * Log register and value mapping since they are useful for
- * baseline MEM ACC logging.
- */
- buflen = num_fuse_sel * sizeof("fuse_selxxxx = XXXX ");
- buf = kzalloc(buflen, GFP_KERNEL);
- if (!buf)
- goto done;
- for (j = 0; j < num_fuse_sel; j++)
- pos += scnprintf(buf + pos, buflen - pos, "fuse_sel%d = %d ",
- j, fuse_val[j]);
- buf[pos] = '\0';
- if (mem_acc_vreg->override_map_match != FUSE_MAP_NO_MATCH)
- pr_info("%s %s tuple match found: %d\n", buf, prop_str,
- mem_acc_vreg->override_map_match);
- else
- pr_err("%s %s tuple match not found\n", buf, prop_str);
- done:
- kfree(fuse_sel);
- kfree(tmp);
- kfree(buf);
- return rc;
- }
- #define MAX_CHARS_PER_INT 20
- static int mem_acc_reg_addr_val_dump(struct mem_acc_regulator *mem_acc_vreg,
- struct corner_acc_reg_config *corner_acc_reg_config,
- u32 corner)
- {
- int i, k, index, pos = 0;
- u32 addr_index;
- size_t buflen;
- char *buf;
- struct acc_reg_value *reg_config_list =
- corner_acc_reg_config->reg_config_list;
- int max_reg_config_len = corner_acc_reg_config->max_reg_config_len;
- int num_corners = mem_acc_vreg->num_corners;
- /*
- * Log register and value mapping since they are useful for
- * baseline MEM ACC logging.
- */
- buflen = max_reg_config_len * (MAX_CHARS_PER_INT + 6) * sizeof(*buf);
- buf = kzalloc(buflen, GFP_KERNEL);
- if (buf == NULL) {
- pr_err("Could not allocate memory for acc register and value logging\n");
- return -ENOMEM;
- }
- for (i = 0; i < num_corners; i++) {
- if (corner == i + 1)
- continue;
- pr_debug("Corner: %d --> %d:\n", corner, i + 1);
- pos = 0;
- for (k = 0; k < max_reg_config_len; k++) {
- index = i * max_reg_config_len + k;
- addr_index = reg_config_list[index].addr_index;
- if (addr_index == PARAM_MATCH_ANY)
- break;
- pos += scnprintf(buf + pos, buflen - pos,
- "<0x%x 0x%x> ",
- mem_acc_vreg->phys_reg_addr_list[addr_index],
- reg_config_list[index].reg_val);
- }
- buf[pos] = '\0';
- pr_debug("%s\n", buf);
- }
- kfree(buf);
- return 0;
- }
- static int mem_acc_get_reg_addr_val(struct device_node *of_node,
- const char *prop_str, struct acc_reg_value *reg_config_list,
- int list_offset, int list_size, u32 max_reg_index)
- {
- int i, index, rc = 0;
- for (i = 0; i < list_size / 2; i++) {
- index = (list_offset * list_size) + i * 2;
- rc = of_property_read_u32_index(of_node, prop_str, index,
- ®_config_list[i].addr_index);
- rc |= of_property_read_u32_index(of_node, prop_str, index + 1,
- ®_config_list[i].reg_val);
- if (rc) {
- pr_err("could not read %s at tuple %u: rc=%d\n",
- prop_str, index, rc);
- return rc;
- }
- if (reg_config_list[i].addr_index == PARAM_MATCH_ANY)
- continue;
- if ((!reg_config_list[i].addr_index) ||
- reg_config_list[i].addr_index > max_reg_index) {
- pr_err("Invalid register index %u in %s at tuple %u\n",
- reg_config_list[i].addr_index, prop_str, index);
- return -EINVAL;
- }
- }
- return rc;
- }
- static int mem_acc_override_reg_addr_val_init(
- struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = mem_acc_vreg->dev->of_node;
- struct corner_acc_reg_config *corner_acc_reg_config;
- struct acc_reg_value *override_reg_config_list;
- int i, tuple_count, tuple_match, len = 0, rc = 0;
- u32 list_size, override_max_reg_config_len;
- char prop_str[40];
- struct property *prop;
- int num_corners = mem_acc_vreg->num_corners;
- if (!mem_acc_vreg->corner_acc_reg_config)
- return 0;
- if (mem_acc_vreg->override_map_count) {
- if (mem_acc_vreg->override_map_match == FUSE_MAP_NO_MATCH)
- return 0;
- tuple_count = mem_acc_vreg->override_map_count;
- tuple_match = mem_acc_vreg->override_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- corner_acc_reg_config = mem_acc_vreg->corner_acc_reg_config;
- for (i = 1; i <= num_corners; i++) {
- snprintf(prop_str, sizeof(prop_str),
- "qcom,override-corner%d-addr-val-map", i);
- prop = of_find_property(of_node, prop_str, &len);
- list_size = len / (tuple_count * sizeof(u32));
- if (!prop) {
- pr_debug("%s property not specified\n", prop_str);
- continue;
- }
- if ((!list_size) || list_size < (num_corners * 2)) {
- pr_err("qcom,override-corner%d-addr-val-map property is missed or invalid length: len=%d\n",
- i, len);
- return -EINVAL;
- }
- override_max_reg_config_len = list_size / (num_corners * 2);
- override_reg_config_list =
- corner_acc_reg_config[i].reg_config_list;
- if (corner_acc_reg_config[i].max_reg_config_len
- != override_max_reg_config_len) {
- /* Free already allocate memory */
- devm_kfree(mem_acc_vreg->dev, override_reg_config_list);
- /* Allocated memory for new requirement */
- override_reg_config_list =
- devm_kcalloc(mem_acc_vreg->dev,
- override_max_reg_config_len * num_corners,
- sizeof(*override_reg_config_list), GFP_KERNEL);
- if (!override_reg_config_list)
- return -ENOMEM;
- corner_acc_reg_config[i].max_reg_config_len =
- override_max_reg_config_len;
- corner_acc_reg_config[i].reg_config_list =
- override_reg_config_list;
- }
- rc = mem_acc_get_reg_addr_val(of_node, prop_str,
- override_reg_config_list, tuple_match,
- list_size, mem_acc_vreg->num_acc_reg);
- if (rc) {
- pr_err("Failed to read %s property: rc=%d\n",
- prop_str, rc);
- return rc;
- }
- rc = mem_acc_reg_addr_val_dump(mem_acc_vreg,
- &corner_acc_reg_config[i], i);
- if (rc) {
- pr_err("could not dump acc address-value dump for corner=%d: rc=%d\n",
- i, rc);
- return rc;
- }
- }
- return rc;
- }
- static int mem_acc_parse_override_config(struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = mem_acc_vreg->dev->of_node;
- int i, rc = 0;
- /* Specify default no match case. */
- mem_acc_vreg->override_map_match = FUSE_MAP_NO_MATCH;
- mem_acc_vreg->override_map_count = 0;
- if (of_find_property(of_node, "qcom,override-fuse-range-map",
- NULL)) {
- rc = mem_acc_parse_override_fuse_version_range(mem_acc_vreg);
- if (rc) {
- pr_err("parsing qcom,override-fuse-range-map property failed, rc=%d\n",
- rc);
- return rc;
- }
- } else if (of_find_property(of_node, "qcom,override-fuse-version-map",
- NULL)) {
- rc = mem_acc_parse_override_fuse_version_map(mem_acc_vreg);
- if (rc) {
- pr_err("parsing qcom,override-fuse-version-map property failed, rc=%d\n",
- rc);
- return rc;
- }
- } else {
- /* No override fuse configuration defined in device node */
- return 0;
- }
- if (mem_acc_vreg->override_map_match == FUSE_MAP_NO_MATCH)
- return 0;
- rc = mem_acc_override_corner_map(mem_acc_vreg);
- if (rc) {
- pr_err("Unable to override corner map rc=%d\n", rc);
- return rc;
- }
- rc = mem_acc_override_reg_addr_val_init(mem_acc_vreg);
- if (rc) {
- pr_err("Unable to override reg_config_list init rc=%d\n",
- rc);
- return rc;
- }
- for (i = 0; i < MEMORY_MAX; i++) {
- rc = override_mem_acc_custom_data(mem_acc_vreg, i);
- if (rc) {
- pr_err("Unable to override custom data for mem_type=%d rc=%d\n",
- i, rc);
- return rc;
- }
- }
- return rc;
- }
- static int mem_acc_init_reg_config(struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = mem_acc_vreg->dev->of_node;
- int i, size, len = 0, rc = 0;
- u32 addr_index, reg_val, index;
- char *prop_str = "qcom,acc-init-reg-config";
- if (!of_find_property(of_node, prop_str, &len)) {
- /* Initial acc register configuration not specified */
- return rc;
- }
- size = len / sizeof(u32);
- if ((!size) || (size % 2)) {
- pr_err("%s specified with invalid length: %d\n",
- prop_str, size);
- return -EINVAL;
- }
- for (i = 0; i < size / 2; i++) {
- index = i * 2;
- rc = of_property_read_u32_index(of_node, prop_str, index,
- &addr_index);
- rc |= of_property_read_u32_index(of_node, prop_str, index + 1,
- ®_val);
- if (rc) {
- pr_err("could not read %s at tuple %u: rc=%d\n",
- prop_str, index, rc);
- return rc;
- }
- if ((!addr_index) || addr_index > mem_acc_vreg->num_acc_reg) {
- pr_err("Invalid register index %u in %s at tuple %u\n",
- addr_index, prop_str, index);
- return -EINVAL;
- }
- writel_relaxed(reg_val,
- mem_acc_vreg->remap_reg_addr_list[addr_index]);
- /* make sure write complete */
- mb();
- pr_debug("acc initial config: register:0x%x value:0x%x\n",
- mem_acc_vreg->phys_reg_addr_list[addr_index], reg_val);
- }
- return rc;
- }
- static int mem_acc_get_reg_addr(struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = mem_acc_vreg->dev->of_node;
- void __iomem **remap_reg_addr_list;
- u32 *phys_reg_addr_list;
- int i, num_acc_reg, len = 0, rc = 0;
- if (!of_find_property(of_node, "qcom,acc-reg-addr-list", &len)) {
- /* acc register address list not specified */
- return rc;
- }
- num_acc_reg = len / sizeof(u32);
- if (!num_acc_reg) {
- pr_err("qcom,acc-reg-addr-list has invalid len = %d\n", len);
- return -EINVAL;
- }
- phys_reg_addr_list = devm_kcalloc(mem_acc_vreg->dev, num_acc_reg + 1,
- sizeof(*phys_reg_addr_list), GFP_KERNEL);
- if (!phys_reg_addr_list)
- return -ENOMEM;
- remap_reg_addr_list = devm_kcalloc(mem_acc_vreg->dev, num_acc_reg + 1,
- sizeof(*remap_reg_addr_list), GFP_KERNEL);
- if (!remap_reg_addr_list)
- return -ENOMEM;
- rc = of_property_read_u32_array(of_node, "qcom,acc-reg-addr-list",
- &phys_reg_addr_list[1], num_acc_reg);
- if (rc) {
- pr_err("Read- qcom,acc-reg-addr-list failed: rc=%d\n", rc);
- return rc;
- }
- for (i = 1; i <= num_acc_reg; i++) {
- remap_reg_addr_list[i] = devm_ioremap(mem_acc_vreg->dev,
- phys_reg_addr_list[i], 0x4);
- if (!remap_reg_addr_list[i]) {
- pr_err("Unable to map register address 0x%x\n",
- phys_reg_addr_list[i]);
- return -EINVAL;
- }
- }
- mem_acc_vreg->num_acc_reg = num_acc_reg;
- mem_acc_vreg->phys_reg_addr_list = phys_reg_addr_list;
- mem_acc_vreg->remap_reg_addr_list = remap_reg_addr_list;
- return rc;
- }
- static int mem_acc_reg_config_init(struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = mem_acc_vreg->dev->of_node;
- struct acc_reg_value *reg_config_list;
- int len, size, rc, i, num_corners;
- struct property *prop;
- char prop_str[30];
- struct corner_acc_reg_config *corner_acc_reg_config;
- rc = of_property_read_u32(of_node, "qcom,num-acc-corners",
- &num_corners);
- if (rc) {
- pr_err("could not read qcom,num-acc-corners: rc=%d\n", rc);
- return rc;
- }
- mem_acc_vreg->num_corners = num_corners;
- rc = of_property_read_u32(of_node, "qcom,boot-acc-corner",
- &mem_acc_vreg->corner);
- if (rc) {
- pr_err("could not read qcom,boot-acc-corner: rc=%d\n", rc);
- return rc;
- }
- pr_debug("boot acc corner = %d\n", mem_acc_vreg->corner);
- corner_acc_reg_config = devm_kcalloc(mem_acc_vreg->dev, num_corners + 1,
- sizeof(*corner_acc_reg_config),
- GFP_KERNEL);
- if (!corner_acc_reg_config)
- return -ENOMEM;
- for (i = 1; i <= num_corners; i++) {
- snprintf(prop_str, sizeof(prop_str),
- "qcom,corner%d-reg-config", i);
- prop = of_find_property(of_node, prop_str, &len);
- size = len / sizeof(u32);
- if ((!prop) || (!size) || size < (num_corners * 2)) {
- pr_err("%s property is missed or invalid length: len=%d\n",
- prop_str, len);
- return -EINVAL;
- }
- reg_config_list = devm_kcalloc(mem_acc_vreg->dev, size / 2,
- sizeof(*reg_config_list), GFP_KERNEL);
- if (!reg_config_list)
- return -ENOMEM;
- rc = mem_acc_get_reg_addr_val(of_node, prop_str,
- reg_config_list, 0, size,
- mem_acc_vreg->num_acc_reg);
- if (rc) {
- pr_err("Failed to read %s property: rc=%d\n",
- prop_str, rc);
- return rc;
- }
- corner_acc_reg_config[i].max_reg_config_len =
- size / (num_corners * 2);
- corner_acc_reg_config[i].reg_config_list = reg_config_list;
- rc = mem_acc_reg_addr_val_dump(mem_acc_vreg,
- &corner_acc_reg_config[i], i);
- if (rc) {
- pr_err("could not dump acc address-value dump for corner=%d: rc=%d\n",
- i, rc);
- return rc;
- }
- }
- mem_acc_vreg->corner_acc_reg_config = corner_acc_reg_config;
- mem_acc_vreg->flags |= MEM_ACC_USE_ADDR_VAL_MAP;
- return rc;
- }
- #define MEM_TYPE_STRING_LEN 20
- static int mem_acc_init(struct platform_device *pdev,
- struct mem_acc_regulator *mem_acc_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- struct resource *res;
- int len, rc, i, j;
- bool acc_type_present = false;
- char tmps[MEM_TYPE_STRING_LEN];
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acc-en");
- if (!res || !res->start) {
- pr_debug("'acc-en' resource missing or not used.\n");
- } else {
- mem_acc_vreg->acc_en_addr = res->start;
- len = res->end - res->start + 1;
- pr_debug("'acc_en_addr' = %pa (len=0x%x)\n", &res->start, len);
- mem_acc_vreg->acc_en_base = devm_ioremap(mem_acc_vreg->dev,
- mem_acc_vreg->acc_en_addr, len);
- if (!mem_acc_vreg->acc_en_base) {
- pr_err("Unable to map 'acc_en_addr' %pa\n",
- &mem_acc_vreg->acc_en_addr);
- return -EINVAL;
- }
- rc = populate_acc_data(mem_acc_vreg, "qcom,acc-en-bit-pos",
- &mem_acc_vreg->acc_en_bit_pos,
- &mem_acc_vreg->num_acc_en);
- if (rc) {
- pr_err("Unable to populate 'qcom,acc-en-bit-pos' rc=%d\n",
- rc);
- return rc;
- }
- }
- rc = mem_acc_efuse_init(pdev, mem_acc_vreg);
- if (rc) {
- pr_err("Wrong eFuse address specified: rc=%d\n", rc);
- return rc;
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acc-sel-l1");
- if (!res || !res->start) {
- pr_debug("'acc-sel-l1' resource missing or not used.\n");
- } else {
- rc = mem_acc_sel_setup(mem_acc_vreg, res, MEMORY_L1);
- if (rc) {
- pr_err("Unable to setup mem-acc for mem_type=%d rc=%d\n",
- MEMORY_L1, rc);
- return rc;
- }
- mem_acc_vreg->mem_acc_supported[MEMORY_L1] = true;
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acc-sel-l2");
- if (!res || !res->start) {
- pr_debug("'acc-sel-l2' resource missing or not used.\n");
- } else {
- rc = mem_acc_sel_setup(mem_acc_vreg, res, MEMORY_L2);
- if (rc) {
- pr_err("Unable to setup mem-acc for mem_type=%d rc=%d\n",
- MEMORY_L2, rc);
- return rc;
- }
- mem_acc_vreg->mem_acc_supported[MEMORY_L2] = true;
- }
- for (i = 0; i < MEM_ACC_TYPE_MAX; i++) {
- snprintf(tmps, MEM_TYPE_STRING_LEN, "mem-acc-type%d", i + 1);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, tmps);
- if (!res || !res->start) {
- pr_debug("'%s' resource missing or not used.\n", tmps);
- } else {
- mem_acc_vreg->mem_acc_type_addr[i] = res->start;
- acc_type_present = true;
- }
- }
- rc = mem_acc_get_reg_addr(mem_acc_vreg);
- if (rc) {
- pr_err("Unable to get acc register addresses: rc=%d\n", rc);
- return rc;
- }
- if (mem_acc_vreg->phys_reg_addr_list) {
- rc = mem_acc_reg_config_init(mem_acc_vreg);
- if (rc) {
- pr_err("acc register address-value map failed: rc=%d\n",
- rc);
- return rc;
- }
- }
- if (of_find_property(of_node, "qcom,corner-acc-map", NULL)) {
- rc = populate_acc_data(mem_acc_vreg, "qcom,corner-acc-map",
- &mem_acc_vreg->corner_acc_map,
- &mem_acc_vreg->num_corners);
- /* Check if at least one valid mem-acc config. is specified */
- for (i = 0; i < MEMORY_MAX; i++) {
- if (mem_acc_vreg->mem_acc_supported[i])
- break;
- }
- if (i == MEMORY_MAX && !acc_type_present) {
- pr_err("No mem-acc configuration specified\n");
- return -EINVAL;
- }
- mem_acc_vreg->flags |= MEM_ACC_USE_CORNER_ACC_MAP;
- }
- if ((mem_acc_vreg->flags & MEM_ACC_USE_CORNER_ACC_MAP) &&
- (mem_acc_vreg->flags & MEM_ACC_USE_ADDR_VAL_MAP)) {
- pr_err("Invalid configuration, both qcom,corner-acc-map and qcom,cornerX-addr-val-map specified\n");
- return -EINVAL;
- }
- pr_debug("num_corners = %d\n", mem_acc_vreg->num_corners);
- if (mem_acc_vreg->num_acc_en)
- mem_acc_en_init(mem_acc_vreg);
- if (mem_acc_vreg->phys_reg_addr_list) {
- rc = mem_acc_init_reg_config(mem_acc_vreg);
- if (rc) {
- pr_err("acc initial register configuration failed: rc=%d\n",
- rc);
- return rc;
- }
- }
- rc = mem_acc_sel_init(mem_acc_vreg);
- if (rc) {
- pr_err("Unable to initialize mem_acc_sel reg rc=%d\n", rc);
- return rc;
- }
- for (i = 0; i < MEMORY_MAX; i++) {
- rc = mem_acc_custom_data_init(pdev, mem_acc_vreg, i);
- if (rc) {
- pr_err("Unable to initialize custom data for mem_type=%d rc=%d\n",
- i, rc);
- return rc;
- }
- }
- rc = mem_acc_parse_override_config(mem_acc_vreg);
- if (rc) {
- pr_err("Unable to parse mem acc override configuration, rc=%d\n",
- rc);
- return rc;
- }
- if (acc_type_present) {
- mem_acc_vreg->mem_acc_type_data = devm_kzalloc(
- mem_acc_vreg->dev, mem_acc_vreg->num_corners *
- MEM_ACC_TYPE_MAX * sizeof(u32), GFP_KERNEL);
- if (!mem_acc_vreg->mem_acc_type_data) {
- pr_err("Unable to allocate memory for mem_acc_type\n");
- return -ENOMEM;
- }
- for (i = 0; i < MEM_ACC_TYPE_MAX; i++) {
- if (mem_acc_vreg->mem_acc_type_addr[i]) {
- snprintf(tmps, MEM_TYPE_STRING_LEN,
- "qcom,mem-acc-type%d", i + 1);
- j = i * mem_acc_vreg->num_corners;
- rc = of_property_read_u32_array(
- mem_acc_vreg->dev->of_node,
- tmps,
- &mem_acc_vreg->mem_acc_type_data[j],
- mem_acc_vreg->num_corners);
- if (rc) {
- pr_err("Unable to get property %s rc=%d\n",
- tmps, rc);
- return rc;
- }
- }
- }
- }
- return 0;
- }
- static int mem_acc_regulator_probe(struct platform_device *pdev)
- {
- struct regulator_config reg_config = {};
- struct mem_acc_regulator *mem_acc_vreg;
- struct regulator_desc *rdesc;
- struct regulator_init_data *init_data;
- int rc;
- if (!pdev->dev.of_node) {
- pr_err("Device tree node is missing\n");
- return -EINVAL;
- }
- init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
- NULL);
- if (!init_data) {
- pr_err("regulator init data is missing\n");
- return -EINVAL;
- }
- init_data->constraints.input_uV = init_data->constraints.max_uV;
- init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
- mem_acc_vreg = devm_kzalloc(&pdev->dev, sizeof(*mem_acc_vreg),
- GFP_KERNEL);
- if (!mem_acc_vreg)
- return -ENOMEM;
- mem_acc_vreg->dev = &pdev->dev;
- rc = mem_acc_init(pdev, mem_acc_vreg);
- if (rc) {
- pr_err("Unable to initialize mem_acc configuration rc=%d\n",
- rc);
- return rc;
- }
- rdesc = &mem_acc_vreg->rdesc;
- rdesc->owner = THIS_MODULE;
- rdesc->type = REGULATOR_VOLTAGE;
- rdesc->ops = &mem_acc_corner_ops;
- rdesc->name = init_data->constraints.name;
- reg_config.dev = &pdev->dev;
- reg_config.init_data = init_data;
- reg_config.driver_data = mem_acc_vreg;
- reg_config.of_node = pdev->dev.of_node;
- mem_acc_vreg->rdev = regulator_register(rdesc, ®_config);
- if (IS_ERR(mem_acc_vreg->rdev)) {
- rc = PTR_ERR(mem_acc_vreg->rdev);
- if (rc != -EPROBE_DEFER)
- pr_err("regulator_register failed: rc=%d\n", rc);
- return rc;
- }
- platform_set_drvdata(pdev, mem_acc_vreg);
- return 0;
- }
- static int mem_acc_regulator_remove(struct platform_device *pdev)
- {
- struct mem_acc_regulator *mem_acc_vreg = platform_get_drvdata(pdev);
- regulator_unregister(mem_acc_vreg->rdev);
- return 0;
- }
- static const struct of_device_id mem_acc_regulator_match_table[] = {
- { .compatible = "qcom,mem-acc-regulator", },
- {}
- };
- static struct platform_driver mem_acc_regulator_driver = {
- .probe = mem_acc_regulator_probe,
- .remove = mem_acc_regulator_remove,
- .driver = {
- .name = "qcom,mem-acc-regulator",
- .of_match_table = mem_acc_regulator_match_table,
- .owner = THIS_MODULE,
- },
- };
- int __init mem_acc_regulator_init(void)
- {
- return platform_driver_register(&mem_acc_regulator_driver);
- }
- postcore_initcall(mem_acc_regulator_init);
- static void __exit mem_acc_regulator_exit(void)
- {
- platform_driver_unregister(&mem_acc_regulator_driver);
- }
- module_exit(mem_acc_regulator_exit);
- MODULE_DESCRIPTION("MEM-ACC-SEL regulator driver");
- MODULE_LICENSE("GPL v2");
|