aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorSujit Reddy Thumma <sthumma@codeaurora.org>2014-09-25 08:32:21 -0400
committerChristoph Hellwig <hch@lst.de>2014-10-01 07:11:18 -0400
commit5c0c28a84af9f9b6061bb4855a30e13d289b4ae1 (patch)
treeee8c321b644d10631c3e232692e41e26e4abe38f /drivers/scsi
parent693ad5ba135d40b1379e40e928123681e2aa2c50 (diff)
ufs: Allow vendor specific initialization
Some vendor specific controller versions might need to configure vendor specific - registers, clocks, voltage regulators etc. to initialize the host controller UTP layer and Uni-Pro stack. Provide some common initialization operations that can be used to configure vendor specifics. The methods can be extended in future, for example, for power mode transitions. The operations are vendor/board specific and hence determined with the help of compatible property in device tree. Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org> Signed-off-by: Dolev Raviv <draviv@codeaurora.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ufs/ufshcd-pci.c8
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c29
-rw-r--r--drivers/scsi/ufs/ufshcd.c161
-rw-r--r--drivers/scsi/ufs/ufshcd.h34
4 files changed, 194 insertions, 38 deletions
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index afaabe2aeac8..7a6edbc55f92 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -164,7 +164,13 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
164 164
165 mmio_base = pcim_iomap_table(pdev)[0]; 165 mmio_base = pcim_iomap_table(pdev)[0];
166 166
167 err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq); 167 err = ufshcd_alloc_host(&pdev->dev, &hba);
168 if (err) {
169 dev_err(&pdev->dev, "Allocation failed\n");
170 return err;
171 }
172
173 err = ufshcd_init(hba, mmio_base, pdev->irq);
168 if (err) { 174 if (err) {
169 dev_err(&pdev->dev, "Initialization failed\n"); 175 dev_err(&pdev->dev, "Initialization failed\n");
170 return err; 176 return err;
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5e4623225422..d727b1a83e95 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -35,9 +35,24 @@
35 35
36#include <linux/platform_device.h> 36#include <linux/platform_device.h>
37#include <linux/pm_runtime.h> 37#include <linux/pm_runtime.h>
38#include <linux/of.h>
38 39
39#include "ufshcd.h" 40#include "ufshcd.h"
40 41
42static const struct of_device_id ufs_of_match[];
43static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
44{
45 if (dev->of_node) {
46 const struct of_device_id *match;
47
48 match = of_match_node(ufs_of_match, dev->of_node);
49 if (match)
50 return (struct ufs_hba_variant_ops *)match->data;
51 }
52
53 return NULL;
54}
55
41#ifdef CONFIG_PM 56#ifdef CONFIG_PM
42/** 57/**
43 * ufshcd_pltfrm_suspend - suspend power management function 58 * ufshcd_pltfrm_suspend - suspend power management function
@@ -138,8 +153,8 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
138 153
139 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 154 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
140 mmio_base = devm_ioremap_resource(dev, mem_res); 155 mmio_base = devm_ioremap_resource(dev, mem_res);
141 if (IS_ERR(mmio_base)) { 156 if (IS_ERR(*(void **)&mmio_base)) {
142 err = PTR_ERR(mmio_base); 157 err = PTR_ERR(*(void **)&mmio_base);
143 goto out; 158 goto out;
144 } 159 }
145 160
@@ -150,10 +165,18 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
150 goto out; 165 goto out;
151 } 166 }
152 167
168 err = ufshcd_alloc_host(dev, &hba);
169 if (err) {
170 dev_err(&pdev->dev, "Allocation failed\n");
171 goto out;
172 }
173
174 hba->vops = get_variant_ops(&pdev->dev);
175
153 pm_runtime_set_active(&pdev->dev); 176 pm_runtime_set_active(&pdev->dev);
154 pm_runtime_enable(&pdev->dev); 177 pm_runtime_enable(&pdev->dev);
155 178
156 err = ufshcd_init(dev, &hba, mmio_base, irq); 179 err = ufshcd_init(hba, mmio_base, irq);
157 if (err) { 180 if (err) {
158 dev_err(dev, "Intialization failed\n"); 181 dev_err(dev, "Intialization failed\n");
159 goto out_disable_rpm; 182 goto out_disable_rpm;
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}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index acf318e338ed..8c6bec05283e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -68,6 +68,8 @@
68#define UFSHCD "ufshcd" 68#define UFSHCD "ufshcd"
69#define UFSHCD_DRIVER_VERSION "0.2" 69#define UFSHCD_DRIVER_VERSION "0.2"
70 70
71struct ufs_hba;
72
71enum dev_cmd_type { 73enum dev_cmd_type {
72 DEV_CMD_TYPE_NOP = 0x0, 74 DEV_CMD_TYPE_NOP = 0x0,
73 DEV_CMD_TYPE_QUERY = 0x1, 75 DEV_CMD_TYPE_QUERY = 0x1,
@@ -152,6 +154,30 @@ struct ufs_dev_cmd {
152 struct ufs_query query; 154 struct ufs_query query;
153}; 155};
154 156
157#define PRE_CHANGE 0
158#define POST_CHANGE 1
159/**
160 * struct ufs_hba_variant_ops - variant specific callbacks
161 * @name: variant name
162 * @init: called when the driver is initialized
163 * @exit: called to cleanup everything done in init
164 * @setup_clocks: called before touching any of the controller registers
165 * @setup_regulators: called before accessing the host controller
166 * @hce_enable_notify: called before and after HCE enable bit is set to allow
167 * variant specific Uni-Pro initialization.
168 * @link_startup_notify: called before and after Link startup is carried out
169 * to allow variant specific Uni-Pro initialization.
170 */
171struct ufs_hba_variant_ops {
172 const char *name;
173 int (*init)(struct ufs_hba *);
174 void (*exit)(struct ufs_hba *);
175 int (*setup_clocks)(struct ufs_hba *, bool);
176 int (*setup_regulators)(struct ufs_hba *, bool);
177 int (*hce_enable_notify)(struct ufs_hba *, bool);
178 int (*link_startup_notify)(struct ufs_hba *, bool);
179};
180
155/** 181/**
156 * struct ufs_hba - per adapter private structure 182 * struct ufs_hba - per adapter private structure
157 * @mmio_base: UFSHCI base register address 183 * @mmio_base: UFSHCI base register address
@@ -171,6 +197,8 @@ struct ufs_dev_cmd {
171 * @nutrs: Transfer Request Queue depth supported by controller 197 * @nutrs: Transfer Request Queue depth supported by controller
172 * @nutmrs: Task Management Queue depth supported by controller 198 * @nutmrs: Task Management Queue depth supported by controller
173 * @ufs_version: UFS Version to which controller complies 199 * @ufs_version: UFS Version to which controller complies
200 * @vops: pointer to variant specific operations
201 * @priv: pointer to variant specific private data
174 * @irq: Irq number of the controller 202 * @irq: Irq number of the controller
175 * @active_uic_cmd: handle of active UIC command 203 * @active_uic_cmd: handle of active UIC command
176 * @uic_cmd_mutex: mutex for uic command 204 * @uic_cmd_mutex: mutex for uic command
@@ -218,6 +246,8 @@ struct ufs_hba {
218 int nutrs; 246 int nutrs;
219 int nutmrs; 247 int nutmrs;
220 u32 ufs_version; 248 u32 ufs_version;
249 struct ufs_hba_variant_ops *vops;
250 void *priv;
221 unsigned int irq; 251 unsigned int irq;
222 252
223 struct uic_command *active_uic_cmd; 253 struct uic_command *active_uic_cmd;
@@ -256,8 +286,8 @@ struct ufs_hba {
256#define ufshcd_readl(hba, reg) \ 286#define ufshcd_readl(hba, reg) \
257 readl((hba)->mmio_base + (reg)) 287 readl((hba)->mmio_base + (reg))
258 288
259int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * , 289int ufshcd_alloc_host(struct device *, struct ufs_hba **);
260 unsigned int); 290int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
261void ufshcd_remove(struct ufs_hba *); 291void ufshcd_remove(struct ufs_hba *);
262 292
263/** 293/**