Merge "ARM: dts: msm: cpr: add DT parameters for fuse redundant on 8x10/8x26"

This commit is contained in:
Linux Build Service Account
2013-07-09 05:21:59 -07:00
committed by Gerrit - the friendly Code Review server
4 changed files with 359 additions and 188 deletions
@@ -13,21 +13,17 @@ CPR regulator device is for Qualcomm RBCPR (RapidBridge CPR) on
Required properties:
- compatible: Must be "qcom,cpr-regulator"
- reg: Register addresses for RBCPR, RBCPR clock
select, PVS eFuse and CPR eFuse
select, PVS and CPR eFuse address
- reg-names: Register names. Must be "rbcpr", "rbcpr_clk",
"pvs_efuse" and "cpr_efuse"
"efuse_addr"
- regulator-name: A string used to describe the regulator
- interrupts: Interrupt line from RBCPR to interrupt controller.
- regulator-min-microvolt: Minimum corner value as min constraint, which
should be 1 for SVS corner
- regulator-max-microvolt: Maximum corner value as max constraint, which
should be 4 for SUPER_TURBO or 3 for TURBO
- qcom,num-efuse-bits: The number of bits used in efuse memory to
represent total number of PVS bins. It should
not exceed a maximum of 5 for total number of
32 bins.
- qcom,pvs-bin-process: A list of integers whose length is equal to 2 to
the power of qcom,num-efuse-bits. The location or
the power of qcom,pvs-fuse[num-of-bits]. The location or
0-based index of an element in the list corresponds
to the bin number. The value of each integer
corresponds to the PVS process speed of the APC
@@ -54,7 +50,7 @@ Required properties:
- qcom,cpr-timer-cons-down: Consecutive number of timer interval (qcom,cpr-timer-delay)
occurred before issuing DOWN interrupt.
- qcom,cpr-irq-line: Internal interrupt route signal of RBCPR, one of 0, 1 or 2.
- qcom,cpr-step-quotient: Number of CPR quotient (RO count) per vdd-apc-supply step
- qcom,cpr-step-quotient: Number of CPR quotient (Ring Oscillator(RO) count) per vdd-apc-supply step
to issue error_steps.
- qcom,cpr-up-threshold: The threshold for CPR to issue interrupt when
error_steps is greater than it when stepping up.
@@ -64,6 +60,62 @@ Required properties:
- qcom,cpr-gcnt-time: The time for gate count in microseconds.
- qcom,cpr-apc-volt-step: The voltage in microvolt per CPR step, such as 5000uV.
- qcom,pvs-fuse-redun-sel: Array of 4 elements to indicate where to read the bits and what value to
compare with in order to decide if the redundant PVS fuse bits would be
used instead of the original bits. The 4 elements with index [0..3] are:
[0] => the fuse row number of the selector
[1] => LSB bit position of the bits
[2] => number of bits
[3] => the value to indicate redundant selection
When the value of the fuse bits specified by first 3 elements equals to
the value in 4th element, redundant PVS fuse bits should be selected.
Otherwise, the original PVS bits should be selected.
- qcom,pvs-fuse: Array of three elements to indicate the bits for PVS fuse. The array
should have index and value like this:
[0] => the PVS fuse row number
[1] => LSB bit position of the bits
[2] => number of bits
- qcom,pvs-fuse-redun: Array of three elements to indicate the bits for redundant PVS fuse.
The array should have index and value like this:
[0] => the redundant PVS fuse row number
[1] => LSB bit position of the bits
[2] => number of bits
- qcom,cpr-fuse-redun-sel: Array of 4 elements to indicate where to read the bits and what value to
compare with in order to decide if the redundant CPR fuse bits would be
used instead of the original bits. The 4 elements with index [0..3] are:
[0] => the fuse row number of the selector
[1] => LSB bit position of the bits
[2] => number of bits
[3] => the value to indicate redundant selection
When the value of the fuse bits specified by first 3 elements equals to
the value in 4th element, redundant CPR fuse bits should be selected.
Otherwise, the original CPR bits should be selected.
- qcom,cpr-fuse-row: Row number of CPR fuse
- qcom,cpr-fuse-bp-cpr-disable: Bit position of the bit to indicate if CPR should be disable
- qcom,cpr-fuse-bp-scheme: Bit position of the bit to indicate if it's a global/local scheme
- qcom,cpr-fuse-target-quot: Array of bit positions in fuse for Target Quotient of all corners.
It should have index and value like this:
[0] => bit position of the LSB bit for SVS target quotient
[1] => bit position of the LSB bit for NOMINAL target quotient
[2] => bit position of the LSB bit for TURBO target quotient
- qcom,cpr-fuse-ro-sel: Array of bit positions in fuse for RO select of all corners.
It should have index and value like this:
[0] => bit position of the LSB bit for SVS RO select bits
[1] => bit position of the LSB bit for NOMINAL RO select bits
[2] => bit position of the LSB bit for TURBO RO select bits
- qcom,cpr-fuse-redun-row: Row number of the redundant CPR fuse
- qcom,cpr-fuse-redun-target-quot: Array of bit positions in fuse for redundant Target Quotient of all corners.
It should have index and value like this:
[0] => bit position of the LSB bit for redundant SVS target quotient
[1] => bit position of the LSB bit for redundant NOMINAL target quotient
[2] => bit position of the LSB bit for redundant TURBO target quotient
- qcom,cpr-fuse-redun-ro-sel: Array of bit positions in eFuse for redundant RO select.
It should have index and value like this:
[0] => bit position of the LSB bit for redundant SVS RO select bits
[1] => bit position of the LSB bit for redundant NOMINAL RO select bits
[2] => bit position of the LSB bit for redundant TURBO RO select bits
Optional properties:
- vdd-mx-supply: Regulator to supply memory power as dependency
@@ -78,6 +130,10 @@ Optional properties:
2 => equal to slow speed corner ceiling
3 => equal to qcom,vdd-mx-vmax
This is required when vdd-mx-supply is present.
- qcom,cpr-fuse-redun-bp-cpr-disable: Redundant bit position of the bit to indicate if CPR should be disable
- qcom,cpr-fuse-redun-bp-scheme: Redundant bit position of the bit to indicate if it's a global/local scheme
This property is required if cpr-fuse-redun-bp-cpr-disable
is present, and vise versa.
- qcom,cpr-enable: Present: CPR enabled by default.
Not Present: CPR disable by default.
@@ -86,13 +142,17 @@ Example:
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
reg = <0xf9018000 0x1000>, <0xfc4b8000 0x1000>;
reg-names = "rbcpr", "efuse_addr";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
qcom,pvs-fuse = <22 6 5>;
qcom,pvs-fuse-redun-sel = <22 24 3 2>;
qcom,pvs-fuse-redun = <22 27 5>;
qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
@@ -115,5 +175,15 @@ Example:
qcom,cpr-idle-clocks = <5>;
qcom,cpr-gcnt-time = <1>;
qcom,cpr-apc-volt-step = <5000>;
qcom,cpr-fuse-row = <138>;
qcom,cpr-fuse-bp-cpr-disable = <36>;
qcom,cpr-fuse-bp-scheme = <37>;
qcom,cpr-fuse-target-quot = <24 12 0>;
qcom,cpr-fuse-ro-sel = <54 38 41>;
qcom,cpr-fuse-redun-sel = <138 57 1 1>;
qcom,cpr-fuse-redun-row = <139>;
qcom,cpr-fuse-redun-target-quot = <24 12 0>;
qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
};
+17 -4
View File
@@ -30,14 +30,17 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
<0xfc4bc450 16>;
reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b8000 0x1000>;
reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
qcom,pvs-fuse-redun-sel = <22 24 3 2>;
qcom,pvs-fuse = <22 6 5>;
qcom,pvs-fuse-redun = <22 27 5>;
qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
qcom,pvs-corner-ceiling-slow = <1155000 1160000 1275000>;
@@ -63,6 +66,16 @@
qcom,vdd-apc-step-down-limit = <1>;
qcom,cpr-apc-volt-step = <5000>;
qcom,cpr-fuse-redun-sel = <138 57 1 1>;
qcom,cpr-fuse-row = <138>;
qcom,cpr-fuse-bp-cpr-disable = <36>;
qcom,cpr-fuse-bp-scheme = <37>;
qcom,cpr-fuse-target-quot = <24 12 0>;
qcom,cpr-fuse-ro-sel = <54 38 41>;
qcom,cpr-fuse-redun-row = <139>;
qcom,cpr-fuse-redun-target-quot = <24 12 0>;
qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
qcom,cpr-enable;
};
};
+23 -8
View File
@@ -30,19 +30,22 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
<0xfc4bc450 16>;
reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b8000 0x1000>;
reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
qcom,pvs-fuse-redun-sel = <53 25 3 2>;
qcom,pvs-fuse = <23 6 5>;
qcom,pvs-fuse-redun = <61 47 5>;
qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1>;
qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
qcom,pvs-corner-ceiling-nom = <1075000 1075000 1200000>;
qcom,pvs-corner-ceiling-fast = <1000000 1000000 1140000>;
vdd-apc-supply = <&pm8110_s2>;
vdd-mx-supply = <&pm8110_l3_ao>;
@@ -62,6 +65,18 @@
qcom,vdd-apc-step-up-limit = <1>;
qcom,vdd-apc-step-down-limit = <1>;
qcom,cpr-apc-volt-step = <5000>;
qcom,cpr-fuse-redun-sel = <53 25 3 2>;
qcom,cpr-fuse-row = <61>;
qcom,cpr-fuse-bp-cpr-disable = <39>;
qcom,cpr-fuse-bp-scheme = <40>;
qcom,cpr-fuse-target-quot = <27 15 3>;
qcom,cpr-fuse-ro-sel = <47 41 44>;
qcom,cpr-fuse-redun-row = <52>;
qcom,cpr-fuse-redun-bp-cpr-disable = <24>;
qcom,cpr-fuse-redun-bp-scheme = <25>;
qcom,cpr-fuse-redun-target-quot = <32 12 0>;
qcom,cpr-fuse-redun-ro-sel = <44 26 29>;
};
};
+238 -165
View File
@@ -125,21 +125,7 @@
#define CPR_FUSE_RO_SEL_BITS 3
#define CPR_FUSE_RO_SEL_BITS_MASK ((1<<CPR_FUSE_RO_SEL_BITS)-1)
#define CPR_FUSE_TARGET_QUOT_TURBO_SHIFT 0
#define CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT 12
#define CPR_FUSE_TARGET_QUOT_SVS_SHIFT 24
#define CPR_FUSE_DISABLE_CPR_SHIFT 36
#define CPR_FUSE_LOCAL_APPROACH_SHIFT 37
#define CPR_FUSE_REDUNDANT_SHIFT 57
/* PVS eFuse parameters */
#define PVS_FUSE_REDUNDANT_SHIFT 24
#define PVS_FUSE_REDUNDANT_BITS 3
#define PVS_FUSE_REDUNDANT_MASK ((1<<PVS_FUSE_REDUNDANT_BITS)-1)
#define PVS_FUSE_BINS_SHIFT 6
#define PVS_FUSE_BINS_REDUNDANT_SHIFT 27
#define BYTES_PER_FUSE_ROW 8
enum voltage_change_dir {
NO_CHANGE,
@@ -154,9 +140,11 @@ struct cpr_regulator {
int corner;
int ceiling_max;
/* eFuse parameters */
phys_addr_t efuse_addr;
void __iomem *efuse_base;
/* Process voltage parameters */
phys_addr_t pvs_efuse;
u32 num_efuse_bits;
u32 pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
u32 pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
/* Process voltage variables */
@@ -173,12 +161,9 @@ struct cpr_regulator {
int vdd_mx_vmin;
/* CPR parameters */
phys_addr_t cpr_fuse_addr;
u64 cpr_fuse_bits;
u64 cpr_fuse_bits_2;
bool cpr_fuse_disable;
bool cpr_fuse_local;
bool cpr_fuse_redundancy;
int cpr_fuse_target_quot[CPR_CORNER_MAX];
int cpr_fuse_ro_sel[CPR_CORNER_MAX];
int gcnt;
@@ -838,7 +823,7 @@ static int cpr_regulator_resume(struct platform_device *pdev)
#define cpr_regulator_resume NULL
#endif
static int cpr_config(struct cpr_regulator *cpr_vreg)
static int __devinit cpr_config(struct cpr_regulator *cpr_vreg)
{
int i;
u32 val, gcnt, reg;
@@ -928,47 +913,80 @@ static int cpr_config(struct cpr_regulator *cpr_vreg)
return 0;
}
static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
static int __devinit cpr_is_fuse_redundant(struct cpr_regulator *cpr_vreg,
u32 redun_sel[4])
{
void __iomem *efuse_base;
u32 efuse_bits, redundant, shift, mask;
int i, process;
u32 fuse_bits;
int redundant;
efuse_base = ioremap(cpr_vreg->pvs_efuse, 4);
if (!efuse_base) {
pr_err("Unable to map pvs_efuse 0x%08x\n",
cpr_vreg->pvs_efuse);
return -EINVAL;
fuse_bits = readl_relaxed(cpr_vreg->efuse_base
+ redun_sel[0] * BYTES_PER_FUSE_ROW);
fuse_bits = (fuse_bits >> redun_sel[1]) & ((1 << redun_sel[2]) - 1);
if (fuse_bits == redun_sel[3])
redundant = 1;
else
redundant = 0;
pr_info("[row:%d] = 0x%x @%d:%d = %d?: redundant=%d\n",
redun_sel[0], fuse_bits,
redun_sel[1], redun_sel[2], redun_sel[3], redundant);
return redundant;
}
static int __devinit cpr_pvs_init(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
u32 efuse_bits;
int rc, process;
u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
bool redundant;
size_t pvs_bins;
rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun-sel",
pvs_fuse_redun_sel, 4);
if (rc < 0) {
pr_err("pvs-fuse-redun-sel missing: rc=%d\n", rc);
return rc;
}
efuse_bits = readl_relaxed(efuse_base);
redundant = cpr_is_fuse_redundant(cpr_vreg, pvs_fuse_redun_sel);
if (redundant) {
rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun",
pvs_fuse, 3);
if (rc < 0) {
pr_err("pvs-fuse-redun missing: rc=%d\n", rc);
return rc;
}
} else {
rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse",
pvs_fuse, 3);
if (rc < 0) {
pr_err("pvs-fuse missing: rc=%d\n", rc);
return rc;
}
}
/* Construct PVS process # from the efuse bits */
redundant = (efuse_bits >> PVS_FUSE_REDUNDANT_SHIFT)
& PVS_FUSE_REDUNDANT_MASK;
if (redundant == 2)
shift = PVS_FUSE_BINS_REDUNDANT_SHIFT;
else
shift = PVS_FUSE_BINS_SHIFT;
mask = (1 << cpr_vreg->num_efuse_bits) - 1;
cpr_vreg->pvs_bin = (efuse_bits >> shift) & mask;
efuse_bits = readl_relaxed(cpr_vreg->efuse_base +
pvs_fuse[0] * BYTES_PER_FUSE_ROW);
cpr_vreg->pvs_bin = (efuse_bits >> pvs_fuse[1]) &
((1 << pvs_fuse[2]) - 1);
/* Set ceiling max and use it for APC_PVS_NO */
cpr_vreg->ceiling_max =
cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
iounmap(efuse_base);
pvs_bins = 1 << pvs_fuse[2];
rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
cpr_vreg->pvs_bin_process,
pvs_bins);
if (rc < 0) {
pr_err("pvs-bin-process missing: rc=%d\n", rc);
return rc;
}
process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
pr_info("[0x%08X] = 0x%08X, n_bits=%d, bin=%d (%d) [redundant=%d]\n",
cpr_vreg->pvs_efuse, efuse_bits, cpr_vreg->num_efuse_bits,
cpr_vreg->pvs_bin, process, redundant);
for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
pr_info("[%d] [%d %d %d] uV\n", i,
cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
}
pr_info("[row:%d] = 0x%08X, n_bits=%d, bin=%d (%d)\n",
pvs_fuse[0], efuse_bits, pvs_fuse[2],
cpr_vreg->pvs_bin, process);
if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
@@ -994,7 +1012,7 @@ do { \
} \
} while (0)
static int __init cpr_apc_init(struct platform_device *pdev,
static int __devinit cpr_apc_init(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
@@ -1055,81 +1073,124 @@ static void cpr_apc_exit(struct cpr_regulator *cpr_vreg)
}
}
static int __init cpr_init_cpr_efuse(struct cpr_regulator *cpr_vreg)
static int __devinit cpr_init_cpr_efuse(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
void __iomem *efuse_base;
struct device_node *of_node = pdev->dev.of_node;
int i, rc = 0;
bool redundant;
u32 cpr_fuse_redun_sel[4];
char *targ_quot_str, *ro_sel_str;
u32 cpr_fuse_row;
u32 bp_cpr_disable, bp_scheme;
int bp_target_quot[CPR_CORNER_MAX];
int bp_ro_sel[CPR_CORNER_MAX];
u32 ro_sel, val;
u64 fuse_bits;
int ro_sel_shift[CPR_CORNER_MAX];
u64 fuse_bits, fuse_bits_2;
efuse_base = ioremap(cpr_vreg->cpr_fuse_addr, 16);
if (!efuse_base) {
pr_err("Unable to map cpr_fuse_addr 0x%08x\n",
cpr_vreg->cpr_fuse_addr);
return -EINVAL;
rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-redun-sel",
cpr_fuse_redun_sel, 4);
if (rc < 0) {
pr_err("cpr-fuse-redun-sel missing: rc=%d\n", rc);
return rc;
}
cpr_vreg->cpr_fuse_bits = readll_relaxed(efuse_base);
cpr_vreg->cpr_fuse_bits_2 = readll_relaxed(efuse_base + 8);
redundant = cpr_is_fuse_redundant(cpr_vreg, cpr_fuse_redun_sel);
iounmap(efuse_base);
if (redundant) {
CPR_PROP_READ_U32(of_node, "cpr-fuse-redun-row",
&cpr_fuse_row, rc);
targ_quot_str = "qcom,cpr-fuse-redun-target-quot";
ro_sel_str = "qcom,cpr-fuse-redun-ro-sel";
} else {
CPR_PROP_READ_U32(of_node, "cpr-fuse-row",
&cpr_fuse_row, rc);
targ_quot_str = "qcom,cpr-fuse-target-quot";
ro_sel_str = "qcom,cpr-fuse-ro-sel";
}
if (rc)
return rc;
rc = of_property_read_u32_array(of_node,
targ_quot_str,
&bp_target_quot[CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("missing %s: rc=%d\n", targ_quot_str, rc);
return rc;
}
rc = of_property_read_u32_array(of_node,
ro_sel_str,
&bp_ro_sel[CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("missing %s: rc=%d\n", ro_sel_str, rc);
return rc;
}
/* Read the control bits of eFuse */
cpr_vreg->cpr_fuse_disable = (cpr_vreg->cpr_fuse_bits >>
CPR_FUSE_DISABLE_CPR_SHIFT) & 0x01;
cpr_vreg->cpr_fuse_local = (cpr_vreg->cpr_fuse_bits >>
CPR_FUSE_LOCAL_APPROACH_SHIFT) & 0x01;
cpr_vreg->cpr_fuse_redundancy = (cpr_vreg->cpr_fuse_bits >>
CPR_FUSE_REDUNDANT_SHIFT) & 0x01;
fuse_bits = readll_relaxed(cpr_vreg->efuse_base
+ cpr_fuse_row * BYTES_PER_FUSE_ROW);
pr_info("[row:%d] = 0x%llx\n", cpr_fuse_row, fuse_bits);
pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr,
cpr_vreg->cpr_fuse_bits);
pr_info("disable = %d, local = %d, redundancy = %d\n",
cpr_vreg->cpr_fuse_disable,
cpr_vreg->cpr_fuse_local,
cpr_vreg->cpr_fuse_redundancy);
pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr + 8,
cpr_vreg->cpr_fuse_bits_2);
if (redundant) {
if (of_property_read_bool(of_node,
"qcom,cpr-fuse-redun-bp-cpr-disable")) {
CPR_PROP_READ_U32(of_node,
"cpr-fuse-redun-bp-cpr-disable",
&bp_cpr_disable, rc);
CPR_PROP_READ_U32(of_node,
"cpr-fuse-redun-bp-scheme",
&bp_scheme, rc);
if (rc)
return rc;
fuse_bits_2 = fuse_bits;
} else {
u32 temp_row;
if (cpr_vreg->cpr_fuse_redundancy == 0) {
fuse_bits = cpr_vreg->cpr_fuse_bits;
ro_sel_shift[CPR_CORNER_SVS] = 54;
ro_sel_shift[CPR_CORNER_NORMAL] = 38;
ro_sel_shift[CPR_CORNER_TURBO] = 41;
/* Use original fuse if no optional property */
CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-cpr-disable",
&bp_cpr_disable, rc);
CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-scheme",
&bp_scheme, rc);
CPR_PROP_READ_U32(of_node, "cpr-fuse-row",
&temp_row, rc);
if (rc)
return rc;
fuse_bits_2 = readll_relaxed(cpr_vreg->efuse_base
+ temp_row * BYTES_PER_FUSE_ROW);
pr_info("[original row:%d] = 0x%llx\n",
temp_row, fuse_bits_2);
}
} else {
fuse_bits = cpr_vreg->cpr_fuse_bits_2;
ro_sel_shift[CPR_CORNER_SVS] = 46;
ro_sel_shift[CPR_CORNER_NORMAL] = 36;
ro_sel_shift[CPR_CORNER_TURBO] = 39;
CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-cpr-disable",
&bp_cpr_disable, rc);
CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-scheme",
&bp_scheme, rc);
if (rc)
return rc;
fuse_bits_2 = fuse_bits;
}
/* SVS */
ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_SVS])
& CPR_FUSE_RO_SEL_BITS_MASK;
val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_SVS_SHIFT)
& CPR_FUSE_TARGET_QUOT_BITS_MASK;
cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_SVS] = val;
cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS] = ro_sel;
pr_info("SVS: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
cpr_vreg->cpr_fuse_disable = (fuse_bits_2 >> bp_cpr_disable) & 0x01;
cpr_vreg->cpr_fuse_local = (fuse_bits_2 >> bp_scheme) & 0x01;
/* Nominal */
ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_NORMAL])
& CPR_FUSE_RO_SEL_BITS_MASK;
val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT)
& CPR_FUSE_TARGET_QUOT_BITS_MASK;
cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_NORMAL] = val;
cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL] = ro_sel;
pr_info("Nominal: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
pr_info("disable = %d, local = %d\n",
cpr_vreg->cpr_fuse_disable, cpr_vreg->cpr_fuse_local);
/* Turbo */
ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_TURBO])
for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
ro_sel = (fuse_bits >> bp_ro_sel[i])
& CPR_FUSE_RO_SEL_BITS_MASK;
val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_TURBO_SHIFT)
val = (fuse_bits >> bp_target_quot[i])
& CPR_FUSE_TARGET_QUOT_BITS_MASK;
cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_TURBO] = val;
cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO] = ro_sel;
pr_info("Turbo: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
cpr_vreg->cpr_fuse_target_quot[i] = val;
cpr_vreg->cpr_fuse_ro_sel[i] = ro_sel;
pr_info("Corner[%d]: ro_sel = %d, target quot = %d\n",
i, ro_sel, val);
}
cpr_vreg->cpr_fuse_bits = fuse_bits;
if (!cpr_vreg->cpr_fuse_bits) {
cpr_vreg->cpr_fuse_disable = 1;
pr_err("cpr_fuse_bits = 0: set cpr_fuse_disable = 1\n");
@@ -1138,7 +1199,7 @@ static int __init cpr_init_cpr_efuse(struct cpr_regulator *cpr_vreg)
return 0;
}
static int __init cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
{
int i;
@@ -1155,7 +1216,7 @@ static int __init cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
return 0;
}
static int __init cpr_init_cpr_parameters(struct platform_device *pdev,
static int __devinit cpr_init_cpr_parameters(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
@@ -1223,20 +1284,12 @@ static int __init cpr_init_cpr_parameters(struct platform_device *pdev,
return rc;
}
static int __init cpr_init_cpr(struct platform_device *pdev,
static int __devinit cpr_init_cpr(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct resource *res;
int rc = 0;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"cpr_efuse");
if (!res || !res->start) {
pr_err("cpr_efuse missing: res=%p\n", res);
return -EINVAL;
}
cpr_vreg->cpr_fuse_addr = res->start;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr_clk");
if (!res || !res->start) {
pr_err("missing rbcpr_clk address: res=%p\n", res);
@@ -1244,7 +1297,7 @@ static int __init cpr_init_cpr(struct platform_device *pdev,
}
cpr_vreg->rbcpr_clk_addr = res->start;
rc = cpr_init_cpr_efuse(cpr_vreg);
rc = cpr_init_cpr_efuse(pdev, cpr_vreg);
if (rc)
return rc;
@@ -1287,44 +1340,41 @@ static int __init cpr_init_cpr(struct platform_device *pdev,
return 0;
}
static int __init cpr_pvs_parse_dt(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
static int __devinit cpr_efuse_init(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct resource *res;
int len;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse_addr");
if (!res || !res->start) {
pr_err("efuse_addr missing: res=%p\n", res);
return -EINVAL;
}
cpr_vreg->efuse_addr = res->start;
len = res->end - res->start + 1;
pr_info("efuse_addr = 0x%x (len=0x%x)\n", res->start, len);
cpr_vreg->efuse_base = ioremap(cpr_vreg->efuse_addr, len);
if (!cpr_vreg->efuse_base) {
pr_err("Unable to map efuse_addr 0x%08x\n",
cpr_vreg->efuse_addr);
return -EINVAL;
}
return 0;
}
static void cpr_efuse_free(struct cpr_regulator *cpr_vreg)
{
iounmap(cpr_vreg->efuse_base);
}
static int __devinit cpr_voltage_plan_init(struct platform_device *pdev,
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
struct resource *res;
int rc;
size_t pvs_bins;
/* Parse process voltage parameters */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pvs_efuse");
if (!res || !res->start) {
pr_err("pvs_efuse missing: res=%p\n", res);
return -EINVAL;
}
cpr_vreg->pvs_efuse = res->start;
rc = of_property_read_u32(of_node, "qcom,num-efuse-bits",
&cpr_vreg->num_efuse_bits);
if (rc < 0) {
pr_err("num-efuse-bits missing: rc=%d\n", rc);
return rc;
}
if (cpr_vreg->num_efuse_bits == 0 ||
cpr_vreg->num_efuse_bits > CPR_PVS_EFUSE_BITS_MAX) {
pr_err("invalid num-efuse-bits : %d\n",
cpr_vreg->num_efuse_bits);
return -EINVAL;
}
pvs_bins = 1 << cpr_vreg->num_efuse_bits;
rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
cpr_vreg->pvs_bin_process,
pvs_bins);
if (rc < 0) {
pr_err("pvs-bin-process missing: rc=%d\n", rc);
return rc;
}
int rc, i;
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-slow",
@@ -1353,6 +1403,17 @@ static int __init cpr_pvs_parse_dt(struct platform_device *pdev,
return rc;
}
/* Set ceiling max and use it for APC_PVS_NO */
cpr_vreg->ceiling_max =
cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
pr_info("[%d] [%d %d %d] uV\n", i,
cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
}
return 0;
}
@@ -1386,31 +1447,39 @@ static int __devinit cpr_regulator_probe(struct platform_device *pdev)
return -ENOMEM;
}
rc = cpr_pvs_parse_dt(pdev, cpr_vreg);
rc = cpr_efuse_init(pdev, cpr_vreg);
if (rc) {
pr_err("Wrong DT parameter specified: rc=%d\n", rc);
pr_err("Wrong eFuse address specified: rc=%d\n", rc);
return rc;
}
rc = cpr_pvs_init(cpr_vreg);
rc = cpr_voltage_plan_init(pdev, cpr_vreg);
if (rc) {
pr_err("Wrong DT parameter specified: rc=%d\n", rc);
goto err_out;
}
rc = cpr_pvs_init(pdev, cpr_vreg);
if (rc) {
pr_err("Initialize PVS wrong: rc=%d\n", rc);
return rc;
goto err_out;
}
rc = cpr_apc_init(pdev, cpr_vreg);
if (rc) {
if (rc != -EPROBE_DEFER)
pr_err("Initialize APC wrong: rc=%d\n", rc);
return rc;
goto err_out;
}
rc = cpr_init_cpr(pdev, cpr_vreg);
if (rc) {
pr_err("Initialize CPR failed: rc=%d\n", rc);
return rc;
goto err_out;
}
cpr_efuse_free(cpr_vreg);
mutex_init(&cpr_vreg->cpr_mutex);
rdesc = &cpr_vreg->rdesc;
@@ -1433,6 +1502,10 @@ static int __devinit cpr_regulator_probe(struct platform_device *pdev)
the_cpr = cpr_vreg;
return 0;
err_out:
cpr_efuse_free(cpr_vreg);
return rc;
}
static int __devexit cpr_regulator_remove(struct platform_device *pdev)