9bc51f1e2da82d2637c00bf18977698fc0c6c13d
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / midgard_for_linux / platform / vexpress / mali_kbase_cpu_vexpress.c
1 /*
2  *
3  * (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
4  *
5  * This program is free software and is provided to you under the terms of the
6  * GNU General Public License version 2 as published by the Free Software
7  * Foundation, and any use by you of this program is subject to the terms
8  * of such GNU licence.
9  *
10  * A copy of the licence is included with the program, and can also be obtained
11  * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12  * Boston, MA  02110-1301, USA.
13  *
14  */
15
16
17
18 #include <linux/io.h>
19 #include <mali_kbase.h>
20 #include "mali_kbase_cpu_vexpress.h"
21
22 #define HZ_IN_MHZ (1000000)
23
24 #define CORETILE_EXPRESS_A9X4_SCC_START (0x100E2000)
25 #define MOTHERBOARD_SYS_CFG_START       (0x10000000)
26 #define SYS_CFGDATA_OFFSET              (0x000000A0)
27 #define SYS_CFGCTRL_OFFSET              (0x000000A4)
28 #define SYS_CFGSTAT_OFFSET              (0x000000A8)
29
30 #define SYS_CFGCTRL_START_BIT_VALUE             (1 << 31)
31 #define READ_REG_BIT_VALUE                      (0 << 30)
32 #define DCC_DEFAULT_BIT_VALUE                   (0 << 26)
33 #define SYS_CFG_OSC_FUNC_BIT_VALUE              (1 << 20)
34 #define SITE_DEFAULT_BIT_VALUE                  (1 << 16)
35 #define BOARD_STACK_POS_DEFAULT_BIT_VALUE       (0 << 12)
36 #define DEVICE_DEFAULT_BIT_VALUE                (2 <<  0)
37 #define SYS_CFG_COMPLETE_BIT_VALUE              (1 <<  0)
38 #define SYS_CFG_ERROR_BIT_VALUE                 (1 <<  1)
39
40 #define FEED_REG_BIT_MASK                       (0x0F)
41 #define FCLK_PA_DIVIDE_BIT_SHIFT                (0x03)
42 #define FCLK_PB_DIVIDE_BIT_SHIFT                (0x07)
43 #define FCLK_PC_DIVIDE_BIT_SHIFT                (0x0B)
44 #define AXICLK_PA_DIVIDE_BIT_SHIFT              (0x0F)
45 #define AXICLK_PB_DIVIDE_BIT_SHIFT              (0x13)
46
47 /* the following three values used for reading
48  * HBI value of the LogicTile daughterboard */
49 #define VE_MOTHERBOARD_PERIPHERALS_SMB_CS7 (0x10000000)
50 #define VE_SYS_PROC_ID1_OFFSET (0x00000088)
51 #define VE_LOGIC_TILE_HBI_MASK (0x00000FFF)
52
53 #define IS_SINGLE_BIT_SET(val, pos) (val&(1<<pos))
54
55 #define CPU_CLOCK_SPEED_UNDEFINED (0)
56
57 static u32 cpu_clock_speed = CPU_CLOCK_SPEED_UNDEFINED;
58
59 static DEFINE_RAW_SPINLOCK(syscfg_lock);
60 /**
61  * kbase_get_vendor_specific_cpu_clock_speed -Retrieves the CPU clock speed
62  * @cpu_clock - the value of CPU clock speed in MHz
63  *
64  * Returns 0 on success, error code otherwise.
65  *
66  * The implementation is platform specific.
67 */
68 int kbase_get_vexpress_cpu_clock_speed(u32 *cpu_clock)
69 {
70         int err = 0;
71         u32 reg_val = 0;
72         u32 osc2_value = 0;
73         u32 pa_divide = 0;
74         u32 pb_divide = 0;
75         u32 pc_divide = 0;
76         void __iomem *syscfg_reg = NULL;
77         void __iomem *scc_reg = NULL;
78
79         if (CPU_CLOCK_SPEED_UNDEFINED != cpu_clock_speed) {
80                 *cpu_clock = cpu_clock_speed;
81                 return 0;
82         }
83
84         /* Init the value in case something goes wrong */
85         *cpu_clock = 0;
86
87         /* Map CPU register into virtual memory */
88         syscfg_reg = ioremap(MOTHERBOARD_SYS_CFG_START, 0x1000);
89         if (syscfg_reg == NULL) {
90                 err = -EIO;
91                 goto syscfg_reg_map_failed;
92         }
93
94         scc_reg = ioremap(CORETILE_EXPRESS_A9X4_SCC_START, 0x1000);
95         if (scc_reg == NULL) {
96                 err = -EIO;
97                 goto scc_reg_map_failed;
98         }
99
100         raw_spin_lock(&syscfg_lock);
101
102         /* Read SYS regs - OSC2 */
103         reg_val = readl(syscfg_reg + SYS_CFGCTRL_OFFSET);
104
105         /* Check if there is any other undergoing request */
106         if (reg_val & SYS_CFGCTRL_START_BIT_VALUE) {
107                 err = -EBUSY;
108                 goto ongoing_request;
109         }
110         /* Reset the CGFGSTAT reg */
111         writel(0, (syscfg_reg + SYS_CFGSTAT_OFFSET));
112
113         writel(SYS_CFGCTRL_START_BIT_VALUE | READ_REG_BIT_VALUE |
114                         DCC_DEFAULT_BIT_VALUE |
115                         SYS_CFG_OSC_FUNC_BIT_VALUE |
116                         SITE_DEFAULT_BIT_VALUE |
117                         BOARD_STACK_POS_DEFAULT_BIT_VALUE |
118                         DEVICE_DEFAULT_BIT_VALUE,
119                         (syscfg_reg + SYS_CFGCTRL_OFFSET));
120         /* Wait for the transaction to complete */
121         while (!(readl(syscfg_reg + SYS_CFGSTAT_OFFSET) &
122                         SYS_CFG_COMPLETE_BIT_VALUE))
123                 ;
124         /* Read SYS_CFGSTAT Register to get the status of submitted
125          * transaction */
126         reg_val = readl(syscfg_reg + SYS_CFGSTAT_OFFSET);
127
128         if (reg_val & SYS_CFG_ERROR_BIT_VALUE) {
129                 /* Error while setting register */
130                 err = -EIO;
131                 goto set_reg_error;
132         }
133
134         osc2_value = readl(syscfg_reg + SYS_CFGDATA_OFFSET);
135         /* Read the SCC CFGRW0 register */
136         reg_val = readl(scc_reg);
137
138         /*
139          * Select the appropriate feed:
140          * CFGRW0[0] - CLKOB
141          * CFGRW0[1] - CLKOC
142          * CFGRW0[2] - FACLK (CLK)B FROM AXICLK PLL)
143          */
144         /* Calculate the  FCLK */
145         if (IS_SINGLE_BIT_SET(reg_val, 0)) {
146                 /* CFGRW0[0] - CLKOB */
147                 /* CFGRW0[6:3] */
148                 pa_divide = ((reg_val & (FEED_REG_BIT_MASK <<
149                                 FCLK_PA_DIVIDE_BIT_SHIFT)) >>
150                                 FCLK_PA_DIVIDE_BIT_SHIFT);
151                 /* CFGRW0[10:7] */
152                 pb_divide = ((reg_val & (FEED_REG_BIT_MASK <<
153                                 FCLK_PB_DIVIDE_BIT_SHIFT)) >>
154                                 FCLK_PB_DIVIDE_BIT_SHIFT);
155                 *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide + 1);
156         } else if (IS_SINGLE_BIT_SET(reg_val, 1)) {
157                 /* CFGRW0[1] - CLKOC */
158                 /* CFGRW0[6:3] */
159                 pa_divide = ((reg_val & (FEED_REG_BIT_MASK <<
160                                 FCLK_PA_DIVIDE_BIT_SHIFT)) >>
161                                 FCLK_PA_DIVIDE_BIT_SHIFT);
162                 /* CFGRW0[14:11] */
163                 pc_divide = ((reg_val & (FEED_REG_BIT_MASK <<
164                                 FCLK_PC_DIVIDE_BIT_SHIFT)) >>
165                                 FCLK_PC_DIVIDE_BIT_SHIFT);
166                 *cpu_clock = osc2_value * (pa_divide + 1) / (pc_divide + 1);
167         } else if (IS_SINGLE_BIT_SET(reg_val, 2)) {
168                 /* CFGRW0[2] - FACLK */
169                 /* CFGRW0[18:15] */
170                 pa_divide = ((reg_val & (FEED_REG_BIT_MASK <<
171                                 AXICLK_PA_DIVIDE_BIT_SHIFT)) >>
172                                 AXICLK_PA_DIVIDE_BIT_SHIFT);
173                 /* CFGRW0[22:19] */
174                 pb_divide = ((reg_val & (FEED_REG_BIT_MASK <<
175                                 AXICLK_PB_DIVIDE_BIT_SHIFT)) >>
176                                 AXICLK_PB_DIVIDE_BIT_SHIFT);
177                 *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide + 1);
178         } else {
179                 err = -EIO;
180         }
181
182 set_reg_error:
183 ongoing_request:
184         raw_spin_unlock(&syscfg_lock);
185         *cpu_clock /= HZ_IN_MHZ;
186
187         if (!err)
188                 cpu_clock_speed = *cpu_clock;
189
190         iounmap(scc_reg);
191
192 scc_reg_map_failed:
193         iounmap(syscfg_reg);
194
195 syscfg_reg_map_failed:
196
197         return err;
198 }
199
200 u32 kbase_get_platform_logic_tile_type(void)
201 {
202         void __iomem *syscfg_reg = NULL;
203         u32 sys_procid1 = 0;
204
205         syscfg_reg = ioremap(VE_MOTHERBOARD_PERIPHERALS_SMB_CS7 + VE_SYS_PROC_ID1_OFFSET, 4);
206
207         sys_procid1 = (NULL != syscfg_reg) ? readl(syscfg_reg) : 0;
208
209         return sys_procid1 & VE_LOGIC_TILE_HBI_MASK;
210 }