1 /* 2 * Renesas RCar Gen3 CPG MSSR driver 3 * 4 * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com> 5 * 6 * Based on the following driver from Linux kernel: 7 * r8a7796 Clock Pulse Generator / Module Standby and Software Reset 8 * 9 * Copyright (C) 2016 Glider bvba 10 * 11 * SPDX-License-Identifier: GPL-2.0+ 12 */ 13 #include <common.h> 14 #include <clk-uclass.h> 15 #include <dm.h> 16 #include <errno.h> 17 #include <wait_bit.h> 18 #include <asm/io.h> 19 20 #include <dt-bindings/clock/renesas-cpg-mssr.h> 21 22 #include "renesas-cpg-mssr.h" 23 24 /* 25 * Module Standby and Software Reset register offets. 26 * 27 * If the registers exist, these are valid for SH-Mobile, R-Mobile, 28 * R-Car Gen2, R-Car Gen3, and RZ/G1. 29 * These are NOT valid for R-Car Gen1 and RZ/A1! 30 */ 31 32 /* 33 * Module Stop Status Register offsets 34 */ 35 36 static const u16 mstpsr[] = { 37 0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4, 38 0x9A0, 0x9A4, 0x9A8, 0x9AC, 39 }; 40 41 #define MSTPSR(i) mstpsr[i] 42 43 44 /* 45 * System Module Stop Control Register offsets 46 */ 47 48 static const u16 smstpcr[] = { 49 0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C, 50 0x990, 0x994, 0x998, 0x99C, 51 }; 52 53 #define SMSTPCR(i) smstpcr[i] 54 55 56 /* Realtime Module Stop Control Register offsets */ 57 #define RMSTPCR(i) (smstpcr[i] - 0x20) 58 59 /* Modem Module Stop Control Register offsets (r8a73a4) */ 60 #define MMSTPCR(i) (smstpcr[i] + 0x20) 61 62 /* Software Reset Clearing Register offsets */ 63 #define SRSTCLR(i) (0x940 + (i) * 4) 64 65 bool renesas_clk_is_mod(struct clk *clk) 66 { 67 return (clk->id >> 16) == CPG_MOD; 68 } 69 70 int renesas_clk_get_mod(struct clk *clk, struct cpg_mssr_info *info, 71 const struct mssr_mod_clk **mssr) 72 { 73 const unsigned long clkid = clk->id & 0xffff; 74 int i; 75 76 for (i = 0; i < info->mod_clk_size; i++) { 77 if (info->mod_clk[i].id != 78 (info->mod_clk_base + MOD_CLK_PACK(clkid))) 79 continue; 80 81 *mssr = &info->mod_clk[i]; 82 return 0; 83 } 84 85 return -ENODEV; 86 } 87 88 int renesas_clk_get_core(struct clk *clk, struct cpg_mssr_info *info, 89 const struct cpg_core_clk **core) 90 { 91 const unsigned long clkid = clk->id & 0xffff; 92 int i; 93 94 for (i = 0; i < info->core_clk_size; i++) { 95 if (info->core_clk[i].id != clkid) 96 continue; 97 98 *core = &info->core_clk[i]; 99 return 0; 100 } 101 102 return -ENODEV; 103 } 104 105 int renesas_clk_get_parent(struct clk *clk, struct cpg_mssr_info *info, 106 struct clk *parent) 107 { 108 const struct cpg_core_clk *core; 109 const struct mssr_mod_clk *mssr; 110 int ret; 111 112 if (renesas_clk_is_mod(clk)) { 113 ret = renesas_clk_get_mod(clk, info, &mssr); 114 if (ret) 115 return ret; 116 117 parent->id = mssr->parent; 118 } else { 119 ret = renesas_clk_get_core(clk, info, &core); 120 if (ret) 121 return ret; 122 123 if (core->type == CLK_TYPE_IN) 124 parent->id = ~0; /* Top-level clock */ 125 else 126 parent->id = core->parent; 127 } 128 129 parent->dev = clk->dev; 130 131 return 0; 132 } 133 134 int renesas_clk_endisable(struct clk *clk, void __iomem *base, bool enable) 135 { 136 const unsigned long clkid = clk->id & 0xffff; 137 const unsigned int reg = clkid / 100; 138 const unsigned int bit = clkid % 100; 139 const u32 bitmask = BIT(bit); 140 141 if (!renesas_clk_is_mod(clk)) 142 return -EINVAL; 143 144 debug("%s[%i] MSTP %lu=%02u/%02u %s\n", __func__, __LINE__, 145 clkid, reg, bit, enable ? "ON" : "OFF"); 146 147 if (enable) { 148 clrbits_le32(base + SMSTPCR(reg), bitmask); 149 return wait_for_bit("MSTP", base + MSTPSR(reg), 150 bitmask, 0, 100, 0); 151 } else { 152 setbits_le32(base + SMSTPCR(reg), bitmask); 153 return 0; 154 } 155 } 156 157 int renesas_clk_remove(void __iomem *base, struct cpg_mssr_info *info) 158 { 159 unsigned int i; 160 161 /* Stop TMU0 */ 162 clrbits_le32(TMU_BASE + TSTR0, TSTR0_STR0); 163 164 /* Stop module clock */ 165 for (i = 0; i < info->mstp_table_size; i++) { 166 clrsetbits_le32(base + SMSTPCR(i), 167 info->mstp_table[i].sdis, 168 info->mstp_table[i].sen); 169 clrsetbits_le32(base + RMSTPCR(i), 170 info->mstp_table[i].rdis, 171 info->mstp_table[i].ren); 172 } 173 174 return 0; 175 } 176