aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ufs/ufshcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/ufs/ufshcd.c')
-rw-r--r--drivers/scsi/ufs/ufshcd.c161
1 files changed, 129 insertions, 32 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ba27215b8034..d0565b07dc8a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * This code is based on drivers/scsi/ufs/ufshcd.c 4 * This code is based on drivers/scsi/ufs/ufshcd.c
5 * Copyright (C) 2011-2013 Samsung India Software Operations 5 * Copyright (C) 2011-2013 Samsung India Software Operations
6 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
6 * 7 *
7 * Authors: 8 * Authors:
8 * Santosh Yaraganavi <santosh.sy@samsung.com> 9 * Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -31,6 +32,9 @@
31 * circumstances will the contributor of this Program be liable for 32 * circumstances will the contributor of this Program be liable for
32 * any damages of any kind arising from your use or distribution of 33 * any damages of any kind arising from your use or distribution of
33 * this program. 34 * this program.
35 *
36 * The Linux Foundation chooses to take subject only to the GPLv2
37 * license terms, and distributes only under these terms.
34 */ 38 */
35 39
36#include <linux/async.h> 40#include <linux/async.h>
@@ -175,13 +179,14 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
175/** 179/**
176 * ufshcd_is_device_present - Check if any device connected to 180 * ufshcd_is_device_present - Check if any device connected to
177 * the host controller 181 * the host controller
178 * @reg_hcs - host controller status register value 182 * @hba: pointer to adapter instance
179 * 183 *
180 * Returns 1 if device present, 0 if no device detected 184 * Returns 1 if device present, 0 if no device detected
181 */ 185 */
182static inline int ufshcd_is_device_present(u32 reg_hcs) 186static inline int ufshcd_is_device_present(struct ufs_hba *hba)
183{ 187{
184 return (DEVICE_PRESENT & reg_hcs) ? 1 : 0; 188 return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
189 DEVICE_PRESENT) ? 1 : 0;
185} 190}
186 191
187/** 192/**
@@ -1798,11 +1803,10 @@ out:
1798 * @hba: per adapter instance 1803 * @hba: per adapter instance
1799 * 1804 *
1800 * To bring UFS host controller to operational state, 1805 * To bring UFS host controller to operational state,
1801 * 1. Check if device is present 1806 * 1. Enable required interrupts
1802 * 2. Enable required interrupts 1807 * 2. Configure interrupt aggregation
1803 * 3. Configure interrupt aggregation 1808 * 3. Program UTRL and UTMRL base addres
1804 * 4. Program UTRL and UTMRL base addres 1809 * 4. Configure run-stop-registers
1805 * 5. Configure run-stop-registers
1806 * 1810 *
1807 * Returns 0 on success, non-zero value on failure 1811 * Returns 0 on success, non-zero value on failure
1808 */ 1812 */
@@ -1811,14 +1815,6 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
1811 int err = 0; 1815 int err = 0;
1812 u32 reg; 1816 u32 reg;
1813 1817
1814 /* check if device present */
1815 reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
1816 if (!ufshcd_is_device_present(reg)) {
1817 dev_err(hba->dev, "cc: Device not present\n");
1818 err = -ENXIO;
1819 goto out;
1820 }
1821
1822 /* Enable required interrupts */ 1818 /* Enable required interrupts */
1823 ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS); 1819 ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
1824 1820
@@ -1839,6 +1835,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
1839 * UCRDY, UTMRLDY and UTRLRDY bits must be 1 1835 * UCRDY, UTMRLDY and UTRLRDY bits must be 1
1840 * DEI, HEI bits must be 0 1836 * DEI, HEI bits must be 0
1841 */ 1837 */
1838 reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
1842 if (!(ufshcd_get_lists_status(reg))) { 1839 if (!(ufshcd_get_lists_status(reg))) {
1843 ufshcd_enable_run_stop_reg(hba); 1840 ufshcd_enable_run_stop_reg(hba);
1844 } else { 1841 } else {
@@ -1885,6 +1882,9 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
1885 msleep(5); 1882 msleep(5);
1886 } 1883 }
1887 1884
1885 if (hba->vops && hba->vops->hce_enable_notify)
1886 hba->vops->hce_enable_notify(hba, PRE_CHANGE);
1887
1888 /* start controller initialization sequence */ 1888 /* start controller initialization sequence */
1889 ufshcd_hba_start(hba); 1889 ufshcd_hba_start(hba);
1890 1890
@@ -1912,6 +1912,10 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
1912 } 1912 }
1913 msleep(5); 1913 msleep(5);
1914 } 1914 }
1915
1916 if (hba->vops && hba->vops->hce_enable_notify)
1917 hba->vops->hce_enable_notify(hba, POST_CHANGE);
1918
1915 return 0; 1919 return 0;
1916} 1920}
1917 1921
@@ -1928,12 +1932,28 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
1928 /* enable UIC related interrupts */ 1932 /* enable UIC related interrupts */
1929 ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); 1933 ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
1930 1934
1935 if (hba->vops && hba->vops->link_startup_notify)
1936 hba->vops->link_startup_notify(hba, PRE_CHANGE);
1937
1931 ret = ufshcd_dme_link_startup(hba); 1938 ret = ufshcd_dme_link_startup(hba);
1932 if (ret) 1939 if (ret)
1933 goto out; 1940 goto out;
1934 1941
1935 ret = ufshcd_make_hba_operational(hba); 1942 /* check if device is detected by inter-connect layer */
1943 if (!ufshcd_is_device_present(hba)) {
1944 dev_err(hba->dev, "%s: Device not present\n", __func__);
1945 ret = -ENXIO;
1946 goto out;
1947 }
1948
1949 /* Include any host controller configuration via UIC commands */
1950 if (hba->vops && hba->vops->link_startup_notify) {
1951 ret = hba->vops->link_startup_notify(hba, POST_CHANGE);
1952 if (ret)
1953 goto out;
1954 }
1936 1955
1956 ret = ufshcd_make_hba_operational(hba);
1937out: 1957out:
1938 if (ret) 1958 if (ret)
1939 dev_err(hba->dev, "link startup failed %d\n", ret); 1959 dev_err(hba->dev, "link startup failed %d\n", ret);
@@ -3173,6 +3193,61 @@ static struct scsi_host_template ufshcd_driver_template = {
3173 .can_queue = UFSHCD_CAN_QUEUE, 3193 .can_queue = UFSHCD_CAN_QUEUE,
3174}; 3194};
3175 3195
3196static int ufshcd_variant_hba_init(struct ufs_hba *hba)
3197{
3198 int err = 0;
3199
3200 if (!hba->vops)
3201 goto out;
3202
3203 if (hba->vops->init) {
3204 err = hba->vops->init(hba);
3205 if (err)
3206 goto out;
3207 }
3208
3209 if (hba->vops->setup_clocks) {
3210 err = hba->vops->setup_clocks(hba, true);
3211 if (err)
3212 goto out_exit;
3213 }
3214
3215 if (hba->vops->setup_regulators) {
3216 err = hba->vops->setup_regulators(hba, true);
3217 if (err)
3218 goto out_clks;
3219 }
3220
3221 goto out;
3222
3223out_clks:
3224 if (hba->vops->setup_clocks)
3225 hba->vops->setup_clocks(hba, false);
3226out_exit:
3227 if (hba->vops->exit)
3228 hba->vops->exit(hba);
3229out:
3230 if (err)
3231 dev_err(hba->dev, "%s: variant %s init failed err %d\n",
3232 __func__, hba->vops ? hba->vops->name : "", err);
3233 return err;
3234}
3235
3236static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
3237{
3238 if (!hba->vops)
3239 return;
3240
3241 if (hba->vops->setup_clocks)
3242 hba->vops->setup_clocks(hba, false);
3243
3244 if (hba->vops->setup_regulators)
3245 hba->vops->setup_regulators(hba, false);
3246
3247 if (hba->vops->exit)
3248 hba->vops->exit(hba);
3249}
3250
3176/** 3251/**
3177 * ufshcd_suspend - suspend power management function 3252 * ufshcd_suspend - suspend power management function
3178 * @hba: per adapter instance 3253 * @hba: per adapter instance
@@ -3257,6 +3332,8 @@ void ufshcd_remove(struct ufs_hba *hba)
3257 ufshcd_hba_stop(hba); 3332 ufshcd_hba_stop(hba);
3258 3333
3259 scsi_host_put(hba->host); 3334 scsi_host_put(hba->host);
3335
3336 ufshcd_variant_hba_exit(hba);
3260} 3337}
3261EXPORT_SYMBOL_GPL(ufshcd_remove); 3338EXPORT_SYMBOL_GPL(ufshcd_remove);
3262 3339
@@ -3277,19 +3354,16 @@ static int ufshcd_set_dma_mask(struct ufs_hba *hba)
3277} 3354}
3278 3355
3279/** 3356/**
3280 * ufshcd_init - Driver initialization routine 3357 * ufshcd_alloc_host - allocate Host Bus Adapter (HBA)
3281 * @dev: pointer to device handle 3358 * @dev: pointer to device handle
3282 * @hba_handle: driver private handle 3359 * @hba_handle: driver private handle
3283 * @mmio_base: base register address
3284 * @irq: Interrupt line of device
3285 * Returns 0 on success, non-zero value on failure 3360 * Returns 0 on success, non-zero value on failure
3286 */ 3361 */
3287int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle, 3362int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
3288 void __iomem *mmio_base, unsigned int irq)
3289{ 3363{
3290 struct Scsi_Host *host; 3364 struct Scsi_Host *host;
3291 struct ufs_hba *hba; 3365 struct ufs_hba *hba;
3292 int err; 3366 int err = 0;
3293 3367
3294 if (!dev) { 3368 if (!dev) {
3295 dev_err(dev, 3369 dev_err(dev,
@@ -3298,13 +3372,6 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
3298 goto out_error; 3372 goto out_error;
3299 } 3373 }
3300 3374
3301 if (!mmio_base) {
3302 dev_err(dev,
3303 "Invalid memory reference for mmio_base is NULL\n");
3304 err = -ENODEV;
3305 goto out_error;
3306 }
3307
3308 host = scsi_host_alloc(&ufshcd_driver_template, 3375 host = scsi_host_alloc(&ufshcd_driver_template,
3309 sizeof(struct ufs_hba)); 3376 sizeof(struct ufs_hba));
3310 if (!host) { 3377 if (!host) {
@@ -3315,9 +3382,40 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
3315 hba = shost_priv(host); 3382 hba = shost_priv(host);
3316 hba->host = host; 3383 hba->host = host;
3317 hba->dev = dev; 3384 hba->dev = dev;
3385 *hba_handle = hba;
3386
3387out_error:
3388 return err;
3389}
3390EXPORT_SYMBOL(ufshcd_alloc_host);
3391
3392/**
3393 * ufshcd_init - Driver initialization routine
3394 * @hba: per-adapter instance
3395 * @mmio_base: base register address
3396 * @irq: Interrupt line of device
3397 * Returns 0 on success, non-zero value on failure
3398 */
3399int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
3400{
3401 int err;
3402 struct Scsi_Host *host = hba->host;
3403 struct device *dev = hba->dev;
3404
3405 if (!mmio_base) {
3406 dev_err(hba->dev,
3407 "Invalid memory reference for mmio_base is NULL\n");
3408 err = -ENODEV;
3409 goto out_error;
3410 }
3411
3318 hba->mmio_base = mmio_base; 3412 hba->mmio_base = mmio_base;
3319 hba->irq = irq; 3413 hba->irq = irq;
3320 3414
3415 err = ufshcd_variant_hba_init(hba);
3416 if (err)
3417 goto out_error;
3418
3321 /* Read capabilities registers */ 3419 /* Read capabilities registers */
3322 ufshcd_hba_capabilities(hba); 3420 ufshcd_hba_capabilities(hba);
3323 3421
@@ -3395,8 +3493,6 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
3395 goto out_remove_scsi_host; 3493 goto out_remove_scsi_host;
3396 } 3494 }
3397 3495
3398 *hba_handle = hba;
3399
3400 /* Hold auto suspend until async scan completes */ 3496 /* Hold auto suspend until async scan completes */
3401 pm_runtime_get_sync(dev); 3497 pm_runtime_get_sync(dev);
3402 3498
@@ -3408,6 +3504,7 @@ out_remove_scsi_host:
3408 scsi_remove_host(hba->host); 3504 scsi_remove_host(hba->host);
3409out_disable: 3505out_disable:
3410 scsi_host_put(host); 3506 scsi_host_put(host);
3507 ufshcd_variant_hba_exit(hba);
3411out_error: 3508out_error:
3412 return err; 3509 return err;
3413} 3510}