1/* 2 * iProc Clock Control Unit 3 * The software model repsresents the hardware clock hierarchy 4 * 5 */ 6#include <linux/kernel.h> 7#include <linux/init.h> 8#include <linux/module.h> 9#include <linux/errno.h> 10#include <linux/err.h> 11#include <linux/clk.h> 12#include <linux/io.h> 13#include <linux/ioport.h> 14#include <linux/delay.h> 15 16#include <asm/clkdev.h> 17#include <mach/clkdev.h> 18 19static struct resource ccu_regs = { 20 .name = "cru_regs", 21 .start = 0x19000000, 22 .end = 0x19000fff, 23 .flags = IORESOURCE_MEM, 24}; 25 26/* 27 * Clock management scheme is a provisional implementation 28 * only intended to retreive the pre-set frequencies for each 29 * of the clocks. 30 */ 31 32/* 33 * Get PLL running status and update output frequency 34 * for ARMPLL channel 0 35 */ 36static int a9pll0_status(struct clk * clk) 37{ 38 u32 regA, regB, regC; 39 u32 pdiv, ndiv_int, ndiv_frac, mdiv; 40 u64 x; 41 42 if( clk->type != CLK_PLL) 43 return -EINVAL; 44 45 BUG_ON( ! clk->regs_base ); 46 BUG_ON( ! clk->parent ); 47 48 /* read status register */ 49 regA = readl( clk->regs_base + 0x0c00 );/* IHOST_PROC_CLK_PLLARMA */ 50 regB = readl( clk->regs_base + 0x0c04 );/* IHOST_PROC_CLK_PLLARMB */ 51 regC = readl( clk->regs_base + 0x0c08 );/* IHOST_PROC_CLK_PLLARMB */ 52 53 /* reg C bit 8 is bypass mode - input frequency to output */ 54 if( (regC & (1 << 8)) == 1 ) 55 { 56 clk->rate = clk->parent->rate; 57 return 0; 58 } 59 60 /* reg A bit 28 is "lock" signal, has to be "1" for proper operation */ 61 if( (regA & (1 << 28)) == 0 ) 62 { 63 clk->rate = 0; 64 return -EIO; 65 } 66 67 /* Update PLL frequency */ 68 69 70 /* pdiv in bits 24..27 (4 bits) */ 71 pdiv = ( regA >> 24 ) & 0xf ; 72 if( pdiv == 0 ) pdiv = 0x10 ; 73 74 /* feedback divider (int) in bits 8..17 (10 bits) */ 75 ndiv_int = ( regA >> 8) & ((1<<10)-1); 76 if( ndiv_int == 0 ) ndiv_int = 1 << 10 ; 77 78 /* feedback divider fraction in reg B, bits 0..19 */ 79 ndiv_frac = regB & ((1<<20)-1); 80 81 /* post-divider is in reg C bits 0..7 */ 82 mdiv = regC & 0xff ; 83 if(mdiv == 0) mdiv = 0x100; 84 85 x = ((u64) ndiv_int << 20) | ndiv_frac ; 86 x = (x * clk->parent->rate ) >> 20 ; 87 (void) do_div( x, pdiv ); 88 89 90 (void) do_div(x, mdiv); 91 clk->rate = (u32)(x); 92 93 return 0; 94} 95 96 97/* 98 * Get PLL running status and update output frequency 99 * for ARMPLL channel 1 100 */ 101static int a9pll1_status(struct clk * clk) 102{ 103 u32 regA, regB, regC, regD; 104 unsigned pdiv, ndiv_int, ndiv_frac, mdiv; 105 u64 x; 106 107 if( clk->type != CLK_PLL) 108 return -EINVAL; 109 110 BUG_ON( ! clk->regs_base ); 111 BUG_ON( ! clk->parent ); 112 113 /* read status register */ 114 regA = readl( clk->regs_base+0xc00 );/* IHOST_PROC_CLK_PLLARMB */ 115 regB = readl( clk->regs_base+0xc04 );/* IHOST_PROC_CLK_PLLARMB */ 116 regC = readl( clk->regs_base+0xc20 );/* IHOST_PROC_CLK_PLLARMCTRL5 */ 117 regD = readl( clk->regs_base+0xc24 );/* IHOST_PROC_CLK_PLLARM_OFFSET*/ 118 119 /* reg C bit 8 is bypass mode - input frequency to output */ 120 if( (regC & (1 << 8)) == 1 ) 121 { 122 clk->rate = clk->parent->rate; 123 return 0; 124 } 125 126 /* reg A bit 28 is "lock" signal, has to be "1" for proper operation */ 127 if( (regA & (1 << 28)) == 0 ) 128 { 129 clk->rate = 0; 130 return -EIO; 131 } 132 133 /* Update PLL frequency */ 134 135 136 /* pdiv in bits 24..27 (4 bits) */ 137 pdiv = ( regA >> 24 ) & 0xf ; 138 if( pdiv == 0 ) pdiv = 0x10 ; 139 140 /* Check if offset mode is active */ 141 if( regD & (1<<29) ) 142 { 143 /* pllarm_ndiv_int_offset bits 27:20 */ 144 ndiv_int = ( regD >> 20 ) & 0xff ; 145 if( ndiv_int == 0 ) ndiv_int = 1 << 8 ; 146 147 /* pllarm_ndiv_frac_offset bits 19:0 */ 148 ndiv_frac = regD & ((1<<20)-1); 149 } 150 /* If offset not active, channel 0 parameters are used */ 151 else 152 { 153 /* feedback divider (int) in bits 8..17 (10 bits) */ 154 ndiv_int = ( regA >> 8) & ((1<<10)-1); 155 if( ndiv_int == 0 ) ndiv_int = 1 << 10 ; 156 157 /* feedback divider fraction in reg B, bits 0..19 */ 158 ndiv_frac = regB & ((1<<20)-1); 159 } 160 /* post-divider is in reg C bits 0..7 */ 161 mdiv = regC & 0xff ; 162 if(mdiv == 0) mdiv = 0x100; 163 164 165 x = ((u64) ndiv_int << 20) | ndiv_frac ; 166 x = (x * clk->parent->rate ) >> 20 ; 167 (void) do_div( x, pdiv ); 168 169 (void) do_div(x, mdiv); 170 clk->rate = (u32)(x); 171 172 return 0; 173} 174 175 176static const struct clk_ops a9pll0_ops = { 177 .status = a9pll0_status, 178}; 179 180static const struct clk_ops a9pll1_ops = { 181 .status = a9pll1_status, 182}; 183 184 185/* 186 * iProc A9 PLL 187 * could be used as source for generated clocks 188 */ 189static struct clk clk_a9pll[2] = { 190 { 191 .ops = &a9pll0_ops, 192 .name = "arm_cpu_clk", 193 .type = CLK_PLL, 194 .chan = 0xa, 195 }, 196 { 197 .ops = &a9pll1_ops, 198 .name = "arm_cpu_h_clk", 199 .type = CLK_PLL, 200 .chan = 0xb, 201 }, 202}; 203 204/* 205 * Decode the Frequency ID setting for arm_clk 206 */ 207static int iproc_cru_arm_freq_id( void * __iomem regs_base ) 208{ 209 u32 reg_f, reg; 210 unsigned policy, fid, i ; 211 u8 arm_clk_policy_mask = 0, apb0_clk_policy_mask = 0 ; 212 213 /* bits 0..2 freq# for policy0, 8..10 for policy1, 214 * 16..18 policy2, 24..26 policy 3 215 */ 216 reg_f = readl( regs_base+0x008 );/*IHOST_PROC_CLK_POLICY_FREQ*/ 217 218 for(i = 0; i < 4; i ++ ) { 219 /* Reg IHOST_PROC_CLK_POLICY<i>_MASK*/ 220 /* bit 20 arm policy mask, bit 21 apb0 policy mask */ 221 reg = readl( regs_base+0x010+i*4 ); 222 arm_clk_policy_mask |= (1 & ( reg >> 20 )) << i; 223 apb0_clk_policy_mask |= (1 & ( reg >> 21 )) << i; 224 } 225 226 /* TBD: Where to get hardware policy setting ? */ 227 policy = 0 ; 228 229 /* Check for PLL policy software override */ 230 reg = readl( regs_base+0xe00 );/* IHOST_PROC_CLK_ARM_DIV */ 231 if( reg & (1 << 4 )) 232 policy = reg & 0xf ; 233 234 fid = (reg_f >> (8 * policy)) & 0xf; 235 236 /* Verify freq_id from debug register */ 237 reg = readl( regs_base+0xec0 );/* IHOST_PROC_CLK_POLICY_DBG */ 238 /* Bits 12..14 contain active frequency_id */ 239 i = 0x7 & (reg >> 12); 240 241 if( fid != i ) { 242 printk(KERN_WARNING 243 "IPROC CRU clock frequency id override %d->%d\n", 244 fid, i ); 245 fid = i ; 246 } 247 248 return fid ; 249} 250 251/* 252 * Get status of any of the ARMPLL output channels 253 */ 254static int a9pll_chan_status(struct clk * clk) 255{ 256 u32 reg; 257 unsigned freq_id, div ; 258 259 if( clk->type != CLK_DIV) 260 return -EINVAL; 261 262 BUG_ON( ! clk->regs_base ); 263 264 freq_id = iproc_cru_arm_freq_id( clk->regs_base ); 265 266 267 switch( clk->chan ) 268 { 269 default: 270 return -EINVAL; 271 272 case 0x3a: /* arm_clk */ 273 if( freq_id == 7 ) { 274 clk->parent = &clk_a9pll[1]; /* arm_clk_h */ 275 div = 1; 276 } 277 else if( freq_id == 6 ) { 278 clk->parent = &clk_a9pll[0]; /* arm_clk */ 279 div = 1; 280 } 281 else if( freq_id == 2 ) { 282 struct clk * clk_lcpll_200; 283 clk_lcpll_200 = 284 clk_get_sys( NULL, "sdio_clk"); 285 BUG_ON( ! clk_lcpll_200 ); 286 clk->parent = clk_lcpll_200; 287 div = 2; 288 } 289 else { 290 clk->parent = clk_a9pll[0].parent; 291 div = 1; 292 } 293 break; 294 295 case 0x0f: /* periph_clk */ 296 div = 2; 297 break; 298 299 case 0x0a: 300 /* IHOST_PROC_CLK_ARM_DIV */ 301 reg = readl( clk->regs_base+0xe00 ); 302 /* apb0_free_div bits 10:8 */ 303 div = ( reg >> 8 ) & 0x7; 304 if( div == 0 ) div = 8; 305 break; 306 307 case 0x0b: 308 /* IHOST_PROC_CLK_ARM_DIV */ 309 reg = readl( clk->regs_base+0xe00 ); 310 /* arm_switch_div bits 6:5 */ 311 div = ( reg >> 5 ) & 0x3 ; 312 if( div == 0 ) div = 4; 313 break; 314 315 case 0x1a: 316 /* IHOST_PROC_CLK_APB_DIV apb_clk_div bits 1:0 */ 317 reg = readl( clk->regs_base+0xa10 ); 318 div = reg & 0x3 ; 319 if( div == 0 ) div = 4; 320 break; 321 322 } 323 324 BUG_ON( ! clk->parent ); 325 /* Parent may have changed, use top-level API to force recursion */ 326 clk->rate = clk_get_rate( clk->parent ) / div ; 327 328 return 0; 329} 330 331 332static const struct clk_ops a9pll_chan_ops = { 333 .status = a9pll_chan_status, 334}; 335 336/* 337 * iProc A9 PLL output clocks 338 */ 339static struct clk clk_a9chan[] = { 340 { .ops = &a9pll_chan_ops, .type = CLK_DIV, .parent = &clk_a9pll[0], 341 .name = "arm_clk", .chan = 0x3a }, 342 { .ops = &a9pll_chan_ops, .type = CLK_DIV, .parent = &clk_a9chan[0], 343 .name = "periph_clk", .chan = 0x0f }, 344 { .ops = &a9pll_chan_ops, .type = CLK_DIV, .parent = &clk_a9chan[0], 345 .name = "apb0_free", .chan = 0x0a }, 346 { .ops = &a9pll_chan_ops, .type = CLK_DIV, .parent = &clk_a9chan[0], 347 .name = "arm_switch", .chan = 0x0b }, 348 { .ops = &a9pll_chan_ops, .type = CLK_DIV, .parent = &clk_a9chan[0], 349 .name = "apb_clk", .chan = 0x1a }, 350}; 351 352static struct clk_lookup cru_clk_lookups[] = { 353 { .con_id= "armpll_clk", .clk= &clk_a9pll[0], }, 354 { .con_id= "armpll_h_clk", .clk= &clk_a9pll[1], }, 355 { .con_id= "arm_clk", .clk= &clk_a9chan[0], }, 356 { .con_id= "periph_clk",.clk= &clk_a9chan[1], }, 357 { .con_id= "apb0_free", .clk= &clk_a9chan[2], }, 358 { .con_id= "axi_clk", .clk= &clk_a9chan[3], }, 359 { .con_id= "apb_clk", .clk= &clk_a9chan[4], }, 360}; 361 362void __init soc_cru_init( struct clk * src_clk ) 363{ 364 void * __iomem reg_base; 365 unsigned i; 366 367 BUG_ON( request_resource( &iomem_resource, &ccu_regs )); 368 369 reg_base = ioremap( ccu_regs.start, resource_size(&ccu_regs)); 370 371 BUG_ON( IS_ERR_OR_NULL(reg_base )); 372 373 /* Initialize clocks */ 374 for(i = 0; i < ARRAY_SIZE(clk_a9pll); i++ ) 375 { 376 clk_a9pll[i].regs_base = reg_base ; 377 clk_a9pll[i].parent = src_clk ; 378 } 379 380 for(i = 0; i < ARRAY_SIZE(clk_a9chan); i++ ) 381 { 382 clk_a9chan[i].regs_base = reg_base ; 383 } 384 385 /* Install clock sources into the lookup table */ 386 clkdev_add_table(cru_clk_lookups, 387 ARRAY_SIZE(cru_clk_lookups)); 388} 389 390void cru_clocks_show( void ) 391{ 392 unsigned i; 393 394 printk( "CRU Clocks:\n" ); 395 for(i = 0; i < ARRAY_SIZE( cru_clk_lookups); i++ ) 396 { 397 printk( "%s: (%s) %lu\n", 398 cru_clk_lookups[i].con_id, 399 cru_clk_lookups[i].clk->name, 400 clk_get_rate( cru_clk_lookups[i].clk ) 401 ); 402 } 403 printk( "CRU Clocks# %u\n", i ); 404} 405 406/* 407 * Perform reset of one of the two cores by means of the IPROC CRU 408 */ 409int soc_cpu_reset(unsigned cpu, bool reset) 410{ 411 void * __iomem reg_base; 412 u32 reg; 413 414 reg_base = clk_a9pll[0].regs_base ; 415 416 if( cpu >= 2 || ! reg_base ) 417 return -EINVAL; 418 419 /* 420 register IHOST_PROC_RST_WR_ACCESS 0x19000F00 421 <password> bits[23:8] Read will return 0. 0x0000 422 <rstmgr_acc> bits[0] Reset manager access enable. 423 This bit must be 1 for any write access to the remaining Reset 424 manager registers. This field is protected from accidental 425 modification. Writing is allowed only when write data 426 bits [23:8] contain A5A5. 427 */ 428 429 /* Enable writing to reset control bits */ 430 writel( 0xa5a5 << 8 | 0x1, reg_base + 0xf00 ); 431 432 /* 433 register IHOST_PROC_RST_A9_CORE_SOFT_RSTN 0x19000F08 434 <a9_core_1_soft_rstn> bit[1] - Soft reset for a9_core_1. 435 When this bit is 0 a9_core_1 will be in reset state. Default=1 436 <a9_core_0_soft_rstn> bit[0] - Soft reset for a9_core_0. 437 When this bit is 0 a9_core_0 will be in reset state. Default=1 438 */ 439 reg = 0x3 ^ (1 << cpu) ; 440 writel( reg, reg_base + 0xf00 ); 441 writel( 0x3, reg_base + 0xf00 ); 442 443 /* Disable writing to reset control bits */ 444 writel( 0x0, reg_base + 0xf00 ); 445 446 return 0; 447} 448