1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Universal Flash Storage Host controller Platform bus based glue driver 4 * Copyright (C) 2011-2013 Samsung India Software Operations 5 * 6 * Authors: 7 * Santosh Yaraganavi <santosh.sy@samsung.com> 8 * Vinayak Holikatti <h.vinayak@samsung.com> 9 */ 10 11 #include <linux/module.h> 12 #include <linux/platform_device.h> 13 #include <linux/pm_runtime.h> 14 #include <linux/of.h> 15 16 #include <ufs/ufshcd.h> 17 #include "ufshcd-pltfrm.h" 18 #include <ufs/unipro.h> 19 20 #define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2 21 22 static int ufshcd_parse_clock_info(struct ufs_hba *hba) 23 { 24 int ret = 0; 25 int cnt; 26 int i; 27 struct device *dev = hba->dev; 28 struct device_node *np = dev->of_node; 29 const char *name; 30 u32 *clkfreq = NULL; 31 struct ufs_clk_info *clki; 32 int len = 0; 33 size_t sz = 0; 34 35 if (!np) 36 goto out; 37 38 cnt = of_property_count_strings(np, "clock-names"); 39 if (!cnt || (cnt == -EINVAL)) { 40 dev_info(dev, "%s: Unable to find clocks, assuming enabled\n", 41 __func__); 42 } else if (cnt < 0) { 43 dev_err(dev, "%s: count clock strings failed, err %d\n", 44 __func__, cnt); 45 ret = cnt; 46 } 47 48 if (cnt <= 0) 49 goto out; 50 51 if (!of_get_property(np, "freq-table-hz", &len)) { 52 dev_info(dev, "freq-table-hz property not specified\n"); 53 goto out; 54 } 55 56 if (len <= 0) 57 goto out; 58 59 sz = len / sizeof(*clkfreq); 60 if (sz != 2 * cnt) { 61 dev_err(dev, "%s len mismatch\n", "freq-table-hz"); 62 ret = -EINVAL; 63 goto out; 64 } 65 66 clkfreq = devm_kcalloc(dev, sz, sizeof(*clkfreq), 67 GFP_KERNEL); 68 if (!clkfreq) { 69 ret = -ENOMEM; 70 goto out; 71 } 72 73 ret = of_property_read_u32_array(np, "freq-table-hz", 74 clkfreq, sz); 75 if (ret && (ret != -EINVAL)) { 76 dev_err(dev, "%s: error reading array %d\n", 77 "freq-table-hz", ret); 78 return ret; 79 } 80 81 for (i = 0; i < sz; i += 2) { 82 ret = of_property_read_string_index(np, "clock-names", i/2, 83 &name); 84 if (ret) 85 goto out; 86 87 clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); 88 if (!clki) { 89 ret = -ENOMEM; 90 goto out; 91 } 92 93 clki->min_freq = clkfreq[i]; 94 clki->max_freq = clkfreq[i+1]; 95 clki->name = devm_kstrdup(dev, name, GFP_KERNEL); 96 if (!clki->name) { 97 ret = -ENOMEM; 98 goto out; 99 } 100 101 if (!strcmp(name, "ref_clk")) 102 clki->keep_link_active = true; 103 dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz", 104 clki->min_freq, clki->max_freq, clki->name); 105 list_add_tail(&clki->list, &hba->clk_list_head); 106 } 107 out: 108 return ret; 109 } 110 111 static bool phandle_exists(const struct device_node *np, 112 const char *phandle_name, int index) 113 { 114 struct device_node *parse_np = of_parse_phandle(np, phandle_name, index); 115 116 if (parse_np) 117 of_node_put(parse_np); 118 119 return parse_np != NULL; 120 } 121 122 #define MAX_PROP_SIZE 32 123 int ufshcd_populate_vreg(struct device *dev, const char *name, 124 struct ufs_vreg **out_vreg) 125 { 126 char prop_name[MAX_PROP_SIZE]; 127 struct ufs_vreg *vreg = NULL; 128 struct device_node *np = dev->of_node; 129 130 if (!np) { 131 dev_err(dev, "%s: non DT initialization\n", __func__); 132 goto out; 133 } 134 135 snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name); 136 if (!phandle_exists(np, prop_name, 0)) { 137 dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n", 138 __func__, prop_name); 139 goto out; 140 } 141 142 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); 143 if (!vreg) 144 return -ENOMEM; 145 146 vreg->name = devm_kstrdup(dev, name, GFP_KERNEL); 147 if (!vreg->name) 148 return -ENOMEM; 149 150 snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name); 151 if (of_property_read_u32(np, prop_name, &vreg->max_uA)) { 152 dev_info(dev, "%s: unable to find %s\n", __func__, prop_name); 153 vreg->max_uA = 0; 154 } 155 out: 156 *out_vreg = vreg; 157 return 0; 158 } 159 EXPORT_SYMBOL_GPL(ufshcd_populate_vreg); 160 161 /** 162 * ufshcd_parse_regulator_info - get regulator info from device tree 163 * @hba: per adapter instance 164 * 165 * Get regulator info from device tree for vcc, vccq, vccq2 power supplies. 166 * If any of the supplies are not defined it is assumed that they are always-on 167 * and hence return zero. If the property is defined but parsing is failed 168 * then return corresponding error. 169 */ 170 static int ufshcd_parse_regulator_info(struct ufs_hba *hba) 171 { 172 int err; 173 struct device *dev = hba->dev; 174 struct ufs_vreg_info *info = &hba->vreg_info; 175 176 err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba); 177 if (err) 178 goto out; 179 180 err = ufshcd_populate_vreg(dev, "vcc", &info->vcc); 181 if (err) 182 goto out; 183 184 err = ufshcd_populate_vreg(dev, "vccq", &info->vccq); 185 if (err) 186 goto out; 187 188 err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2); 189 out: 190 return err; 191 } 192 193 static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba) 194 { 195 struct device *dev = hba->dev; 196 int ret; 197 198 ret = of_property_read_u32(dev->of_node, "lanes-per-direction", 199 &hba->lanes_per_direction); 200 if (ret) { 201 dev_dbg(hba->dev, 202 "%s: failed to read lanes-per-direction, ret=%d\n", 203 __func__, ret); 204 hba->lanes_per_direction = UFSHCD_DEFAULT_LANES_PER_DIRECTION; 205 } 206 } 207 208 /** 209 * ufshcd_get_pwr_dev_param - get finally agreed attributes for 210 * power mode change 211 * @pltfrm_param: pointer to platform parameters 212 * @dev_max: pointer to device attributes 213 * @agreed_pwr: returned agreed attributes 214 * 215 * Returns 0 on success, non-zero value on failure 216 */ 217 int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, 218 const struct ufs_pa_layer_attr *dev_max, 219 struct ufs_pa_layer_attr *agreed_pwr) 220 { 221 int min_pltfrm_gear; 222 int min_dev_gear; 223 bool is_dev_sup_hs = false; 224 bool is_pltfrm_max_hs = false; 225 226 if (dev_max->pwr_rx == FAST_MODE) 227 is_dev_sup_hs = true; 228 229 if (pltfrm_param->desired_working_mode == UFS_HS_MODE) { 230 is_pltfrm_max_hs = true; 231 min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear, 232 pltfrm_param->hs_tx_gear); 233 } else { 234 min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear, 235 pltfrm_param->pwm_tx_gear); 236 } 237 238 /* 239 * device doesn't support HS but 240 * pltfrm_param->desired_working_mode is HS, 241 * thus device and pltfrm_param don't agree 242 */ 243 if (!is_dev_sup_hs && is_pltfrm_max_hs) { 244 pr_info("%s: device doesn't support HS\n", 245 __func__); 246 return -ENOTSUPP; 247 } else if (is_dev_sup_hs && is_pltfrm_max_hs) { 248 /* 249 * since device supports HS, it supports FAST_MODE. 250 * since pltfrm_param->desired_working_mode is also HS 251 * then final decision (FAST/FASTAUTO) is done according 252 * to pltfrm_params as it is the restricting factor 253 */ 254 agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs; 255 agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; 256 } else { 257 /* 258 * here pltfrm_param->desired_working_mode is PWM. 259 * it doesn't matter whether device supports HS or PWM, 260 * in both cases pltfrm_param->desired_working_mode will 261 * determine the mode 262 */ 263 agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm; 264 agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; 265 } 266 267 /* 268 * we would like tx to work in the minimum number of lanes 269 * between device capability and vendor preferences. 270 * the same decision will be made for rx 271 */ 272 agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, 273 pltfrm_param->tx_lanes); 274 agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, 275 pltfrm_param->rx_lanes); 276 277 /* device maximum gear is the minimum between device rx and tx gears */ 278 min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); 279 280 /* 281 * if both device capabilities and vendor pre-defined preferences are 282 * both HS or both PWM then set the minimum gear to be the chosen 283 * working gear. 284 * if one is PWM and one is HS then the one that is PWM get to decide 285 * what is the gear, as it is the one that also decided previously what 286 * pwr the device will be configured to. 287 */ 288 if ((is_dev_sup_hs && is_pltfrm_max_hs) || 289 (!is_dev_sup_hs && !is_pltfrm_max_hs)) { 290 agreed_pwr->gear_rx = 291 min_t(u32, min_dev_gear, min_pltfrm_gear); 292 } else if (!is_dev_sup_hs) { 293 agreed_pwr->gear_rx = min_dev_gear; 294 } else { 295 agreed_pwr->gear_rx = min_pltfrm_gear; 296 } 297 agreed_pwr->gear_tx = agreed_pwr->gear_rx; 298 299 agreed_pwr->hs_rate = pltfrm_param->hs_rate; 300 301 return 0; 302 } 303 EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); 304 305 void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) 306 { 307 *dev_param = (struct ufs_dev_params){ 308 .tx_lanes = 2, 309 .rx_lanes = 2, 310 .hs_rx_gear = UFS_HS_G3, 311 .hs_tx_gear = UFS_HS_G3, 312 .pwm_rx_gear = UFS_PWM_G4, 313 .pwm_tx_gear = UFS_PWM_G4, 314 .rx_pwr_pwm = SLOW_MODE, 315 .tx_pwr_pwm = SLOW_MODE, 316 .rx_pwr_hs = FAST_MODE, 317 .tx_pwr_hs = FAST_MODE, 318 .hs_rate = PA_HS_MODE_B, 319 .desired_working_mode = UFS_HS_MODE, 320 }; 321 } 322 EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param); 323 324 /** 325 * ufshcd_pltfrm_init - probe routine of the driver 326 * @pdev: pointer to Platform device handle 327 * @vops: pointer to variant ops 328 * 329 * Returns 0 on success, non-zero value on failure 330 */ 331 int ufshcd_pltfrm_init(struct platform_device *pdev, 332 const struct ufs_hba_variant_ops *vops) 333 { 334 struct ufs_hba *hba; 335 void __iomem *mmio_base; 336 int irq, err; 337 struct device *dev = &pdev->dev; 338 339 mmio_base = devm_platform_ioremap_resource(pdev, 0); 340 if (IS_ERR(mmio_base)) { 341 err = PTR_ERR(mmio_base); 342 goto out; 343 } 344 345 irq = platform_get_irq(pdev, 0); 346 if (irq < 0) { 347 err = irq; 348 goto out; 349 } 350 351 err = ufshcd_alloc_host(dev, &hba); 352 if (err) { 353 dev_err(dev, "Allocation failed\n"); 354 goto out; 355 } 356 357 hba->vops = vops; 358 359 err = ufshcd_parse_clock_info(hba); 360 if (err) { 361 dev_err(dev, "%s: clock parse failed %d\n", 362 __func__, err); 363 goto dealloc_host; 364 } 365 err = ufshcd_parse_regulator_info(hba); 366 if (err) { 367 dev_err(dev, "%s: regulator init failed %d\n", 368 __func__, err); 369 goto dealloc_host; 370 } 371 372 ufshcd_init_lanes_per_dir(hba); 373 374 err = ufshcd_init(hba, mmio_base, irq); 375 if (err) { 376 dev_err(dev, "Initialization failed\n"); 377 goto dealloc_host; 378 } 379 380 pm_runtime_set_active(dev); 381 pm_runtime_enable(dev); 382 383 return 0; 384 385 dealloc_host: 386 ufshcd_dealloc_host(hba); 387 out: 388 return err; 389 } 390 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init); 391 392 MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); 393 MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); 394 MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver"); 395 MODULE_LICENSE("GPL"); 396