1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <errno.h>
9*54fd6939SJiyong Park
10*54fd6939SJiyong Park #include <common/debug.h>
11*54fd6939SJiyong Park #include <drivers/delay_timer.h>
12*54fd6939SJiyong Park #include <lib/mmio.h>
13*54fd6939SJiyong Park
14*54fd6939SJiyong Park #include <hi3660.h>
15*54fd6939SJiyong Park #include "hikey960_private.h"
16*54fd6939SJiyong Park
17*54fd6939SJiyong Park #define ADC_ADCIN0 0
18*54fd6939SJiyong Park #define ADC_ADCIN1 1
19*54fd6939SJiyong Park #define ADC_ADCIN2 2
20*54fd6939SJiyong Park
21*54fd6939SJiyong Park #define HKADC_DATA_GRADE0 0
22*54fd6939SJiyong Park #define HKADC_DATA_GRADE1 100
23*54fd6939SJiyong Park #define HKADC_DATA_GRADE2 300
24*54fd6939SJiyong Park #define HKADC_DATA_GRADE3 500
25*54fd6939SJiyong Park #define HKADC_DATA_GRADE4 700
26*54fd6939SJiyong Park #define HKADC_DATA_GRADE5 900
27*54fd6939SJiyong Park #define HKADC_DATA_GRADE6 1100
28*54fd6939SJiyong Park #define HKADC_DATA_GRADE7 1300
29*54fd6939SJiyong Park #define HKADC_DATA_GRADE8 1500
30*54fd6939SJiyong Park #define HKADC_DATA_GRADE9 1700
31*54fd6939SJiyong Park #define HKADC_DATA_GRADE10 1800
32*54fd6939SJiyong Park
33*54fd6939SJiyong Park #define BOARDID_VALUE0 0
34*54fd6939SJiyong Park #define BOARDID_VALUE1 1
35*54fd6939SJiyong Park #define BOARDID_VALUE2 2
36*54fd6939SJiyong Park #define BOARDID_VALUE3 3
37*54fd6939SJiyong Park #define BOARDID_VALUE4 4
38*54fd6939SJiyong Park #define BOARDID_VALUE5 5
39*54fd6939SJiyong Park #define BOARDID_VALUE6 6
40*54fd6939SJiyong Park #define BOARDID_VALUE7 7
41*54fd6939SJiyong Park #define BOARDID_VALUE8 8
42*54fd6939SJiyong Park #define BOARDID_VALUE9 9
43*54fd6939SJiyong Park #define BOARDID_UNKNOWN 0xF
44*54fd6939SJiyong Park
45*54fd6939SJiyong Park #define BOARDID3_BASE 5
46*54fd6939SJiyong Park
47*54fd6939SJiyong Park
init_adc(void)48*54fd6939SJiyong Park static void init_adc(void)
49*54fd6939SJiyong Park {
50*54fd6939SJiyong Park /* reset hkadc */
51*54fd6939SJiyong Park mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
52*54fd6939SJiyong Park /* wait a few clock cycles */
53*54fd6939SJiyong Park udelay(2);
54*54fd6939SJiyong Park mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
55*54fd6939SJiyong Park udelay(2);
56*54fd6939SJiyong Park /* enable hkadc clock */
57*54fd6939SJiyong Park mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
58*54fd6939SJiyong Park udelay(2);
59*54fd6939SJiyong Park mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
60*54fd6939SJiyong Park udelay(2);
61*54fd6939SJiyong Park }
62*54fd6939SJiyong Park
get_adc(unsigned int channel,unsigned int * value)63*54fd6939SJiyong Park static int get_adc(unsigned int channel, unsigned int *value)
64*54fd6939SJiyong Park {
65*54fd6939SJiyong Park unsigned int data, value1, value0;
66*54fd6939SJiyong Park
67*54fd6939SJiyong Park if (channel > HKADC_CHANNEL_MAX) {
68*54fd6939SJiyong Park WARN("invalid channel:%d\n", channel);
69*54fd6939SJiyong Park return -EFAULT;
70*54fd6939SJiyong Park }
71*54fd6939SJiyong Park /* configure the read/write operation for external HKADC */
72*54fd6939SJiyong Park mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
73*54fd6939SJiyong Park mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
74*54fd6939SJiyong Park mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
75*54fd6939SJiyong Park /* configure the number of accessing registers */
76*54fd6939SJiyong Park mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
77*54fd6939SJiyong Park /* configure delay of accessing registers */
78*54fd6939SJiyong Park mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
79*54fd6939SJiyong Park mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
80*54fd6939SJiyong Park
81*54fd6939SJiyong Park /* start HKADC */
82*54fd6939SJiyong Park mmio_write_32(HKADC_DSP_START_REG, 1);
83*54fd6939SJiyong Park do {
84*54fd6939SJiyong Park data = mmio_read_32(HKADC_DSP_START_REG);
85*54fd6939SJiyong Park } while (data & 1);
86*54fd6939SJiyong Park
87*54fd6939SJiyong Park /* convert AD result */
88*54fd6939SJiyong Park value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
89*54fd6939SJiyong Park value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
90*54fd6939SJiyong Park
91*54fd6939SJiyong Park data = ((value1 << 4) & HKADC_VALUE_HIGH) |
92*54fd6939SJiyong Park ((value0 >> 4) & HKADC_VALUE_LOW);
93*54fd6939SJiyong Park *value = data;
94*54fd6939SJiyong Park return 0;
95*54fd6939SJiyong Park }
96*54fd6939SJiyong Park
get_value(unsigned int channel,unsigned int * value)97*54fd6939SJiyong Park static int get_value(unsigned int channel, unsigned int *value)
98*54fd6939SJiyong Park {
99*54fd6939SJiyong Park int ret;
100*54fd6939SJiyong Park
101*54fd6939SJiyong Park ret = get_adc(channel, value);
102*54fd6939SJiyong Park if (ret)
103*54fd6939SJiyong Park return ret;
104*54fd6939SJiyong Park
105*54fd6939SJiyong Park /* convert ADC value to micro-volt */
106*54fd6939SJiyong Park ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
107*54fd6939SJiyong Park *value = ret;
108*54fd6939SJiyong Park return 0;
109*54fd6939SJiyong Park }
110*54fd6939SJiyong Park
adcin_data_remap(unsigned int adcin_value)111*54fd6939SJiyong Park static int adcin_data_remap(unsigned int adcin_value)
112*54fd6939SJiyong Park {
113*54fd6939SJiyong Park int ret;
114*54fd6939SJiyong Park
115*54fd6939SJiyong Park if (adcin_value < HKADC_DATA_GRADE1)
116*54fd6939SJiyong Park ret = BOARDID_VALUE0;
117*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE2)
118*54fd6939SJiyong Park ret = BOARDID_VALUE1;
119*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE3)
120*54fd6939SJiyong Park ret = BOARDID_VALUE2;
121*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE4)
122*54fd6939SJiyong Park ret = BOARDID_VALUE3;
123*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE5)
124*54fd6939SJiyong Park ret = BOARDID_VALUE4;
125*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE6)
126*54fd6939SJiyong Park ret = BOARDID_VALUE5;
127*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE7)
128*54fd6939SJiyong Park ret = BOARDID_VALUE6;
129*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE8)
130*54fd6939SJiyong Park ret = BOARDID_VALUE7;
131*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE9)
132*54fd6939SJiyong Park ret = BOARDID_VALUE8;
133*54fd6939SJiyong Park else if (adcin_value < HKADC_DATA_GRADE10)
134*54fd6939SJiyong Park ret = BOARDID_VALUE9;
135*54fd6939SJiyong Park else
136*54fd6939SJiyong Park ret = BOARDID_UNKNOWN;
137*54fd6939SJiyong Park return ret;
138*54fd6939SJiyong Park }
139*54fd6939SJiyong Park
hikey960_read_boardid(unsigned int * id)140*54fd6939SJiyong Park int hikey960_read_boardid(unsigned int *id)
141*54fd6939SJiyong Park {
142*54fd6939SJiyong Park unsigned int adcin0, adcin1, adcin2;
143*54fd6939SJiyong Park unsigned int adcin0_remap, adcin1_remap, adcin2_remap;
144*54fd6939SJiyong Park
145*54fd6939SJiyong Park assert(id != NULL);
146*54fd6939SJiyong Park
147*54fd6939SJiyong Park init_adc();
148*54fd6939SJiyong Park
149*54fd6939SJiyong Park /* read ADC channel0 data */
150*54fd6939SJiyong Park get_value(ADC_ADCIN0, &adcin0);
151*54fd6939SJiyong Park adcin0_remap = adcin_data_remap(adcin0);
152*54fd6939SJiyong Park if (adcin0_remap == BOARDID_UNKNOWN)
153*54fd6939SJiyong Park return -EINVAL;
154*54fd6939SJiyong Park /* read ADC channel1 data */
155*54fd6939SJiyong Park get_value(ADC_ADCIN1, &adcin1);
156*54fd6939SJiyong Park adcin1_remap = adcin_data_remap(adcin1);
157*54fd6939SJiyong Park if (adcin1_remap == BOARDID_UNKNOWN)
158*54fd6939SJiyong Park return -EINVAL;
159*54fd6939SJiyong Park /* read ADC channel2 data */
160*54fd6939SJiyong Park get_value(ADC_ADCIN2, &adcin2);
161*54fd6939SJiyong Park adcin2_remap = adcin_data_remap(adcin2);
162*54fd6939SJiyong Park if (adcin2_remap == BOARDID_UNKNOWN)
163*54fd6939SJiyong Park return -EINVAL;
164*54fd6939SJiyong Park *id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
165*54fd6939SJiyong Park (adcin1_remap * 10) + adcin0_remap;
166*54fd6939SJiyong Park return 0;
167*54fd6939SJiyong Park }
168