176884cb2SLee Jones /* 276884cb2SLee Jones * Copyright (C) 2012 STMicroelectronics Limited 376884cb2SLee Jones * 476884cb2SLee Jones * Authors: Francesco Virlinzi <francesco.virlinzi@st.com> 576884cb2SLee Jones * Alexandre Torgue <alexandre.torgue@st.com> 676884cb2SLee Jones * 776884cb2SLee Jones * This program is free software; you can redistribute it and/or modify 876884cb2SLee Jones * it under the terms of the GNU General Public License version 2 as 976884cb2SLee Jones * published by the Free Software Foundation. 1076884cb2SLee Jones */ 1176884cb2SLee Jones 1276884cb2SLee Jones #include <linux/init.h> 1376884cb2SLee Jones #include <linux/module.h> 1476884cb2SLee Jones #include <linux/export.h> 1576884cb2SLee Jones #include <linux/platform_device.h> 1676884cb2SLee Jones #include <linux/clk.h> 1776884cb2SLee Jones #include <linux/of.h> 1876884cb2SLee Jones #include <linux/ahci_platform.h> 1976884cb2SLee Jones #include <linux/libata.h> 2076884cb2SLee Jones #include <linux/reset.h> 2176884cb2SLee Jones #include <linux/io.h> 2276884cb2SLee Jones #include <linux/dma-mapping.h> 2376884cb2SLee Jones 2476884cb2SLee Jones #include "ahci.h" 2576884cb2SLee Jones 26018d5ef2SAkinobu Mita #define DRV_NAME "st_ahci" 27018d5ef2SAkinobu Mita 2876884cb2SLee Jones #define ST_AHCI_OOBR 0xbc 2976884cb2SLee Jones #define ST_AHCI_OOBR_WE BIT(31) 3076884cb2SLee Jones #define ST_AHCI_OOBR_CWMIN_SHIFT 24 3176884cb2SLee Jones #define ST_AHCI_OOBR_CWMAX_SHIFT 16 3276884cb2SLee Jones #define ST_AHCI_OOBR_CIMIN_SHIFT 8 3376884cb2SLee Jones #define ST_AHCI_OOBR_CIMAX_SHIFT 0 3476884cb2SLee Jones 3576884cb2SLee Jones struct st_ahci_drv_data { 3676884cb2SLee Jones struct platform_device *ahci; 3776884cb2SLee Jones struct reset_control *pwr; 3876884cb2SLee Jones struct reset_control *sw_rst; 3976884cb2SLee Jones struct reset_control *pwr_rst; 4076884cb2SLee Jones struct ahci_host_priv *hpriv; 4176884cb2SLee Jones }; 4276884cb2SLee Jones 4376884cb2SLee Jones static void st_ahci_configure_oob(void __iomem *mmio) 4476884cb2SLee Jones { 4576884cb2SLee Jones unsigned long old_val, new_val; 4676884cb2SLee Jones 4776884cb2SLee Jones new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) | 4876884cb2SLee Jones (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) | 4976884cb2SLee Jones (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) | 5076884cb2SLee Jones (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT); 5176884cb2SLee Jones 5276884cb2SLee Jones old_val = readl(mmio + ST_AHCI_OOBR); 5376884cb2SLee Jones writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR); 5476884cb2SLee Jones writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR); 5576884cb2SLee Jones writel(new_val, mmio + ST_AHCI_OOBR); 5676884cb2SLee Jones } 5776884cb2SLee Jones 5876884cb2SLee Jones static int st_ahci_deassert_resets(struct device *dev) 5976884cb2SLee Jones { 6076884cb2SLee Jones struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); 6176884cb2SLee Jones int err; 6276884cb2SLee Jones 6376884cb2SLee Jones if (drv_data->pwr) { 6476884cb2SLee Jones err = reset_control_deassert(drv_data->pwr); 6576884cb2SLee Jones if (err) { 6676884cb2SLee Jones dev_err(dev, "unable to bring out of pwrdwn\n"); 6776884cb2SLee Jones return err; 6876884cb2SLee Jones } 6976884cb2SLee Jones } 7076884cb2SLee Jones 7176884cb2SLee Jones if (drv_data->sw_rst) { 7276884cb2SLee Jones err = reset_control_deassert(drv_data->sw_rst); 7376884cb2SLee Jones if (err) { 7476884cb2SLee Jones dev_err(dev, "unable to bring out of sw-rst\n"); 7576884cb2SLee Jones return err; 7676884cb2SLee Jones } 7776884cb2SLee Jones } 7876884cb2SLee Jones 7976884cb2SLee Jones if (drv_data->pwr_rst) { 8076884cb2SLee Jones err = reset_control_deassert(drv_data->pwr_rst); 8176884cb2SLee Jones if (err) { 8276884cb2SLee Jones dev_err(dev, "unable to bring out of pwr-rst\n"); 8376884cb2SLee Jones return err; 8476884cb2SLee Jones } 8576884cb2SLee Jones } 8676884cb2SLee Jones 8776884cb2SLee Jones return 0; 8876884cb2SLee Jones } 8976884cb2SLee Jones 90b032378bSBartlomiej Zolnierkiewicz static void st_ahci_host_stop(struct ata_host *host) 91a8237084SLee Jones { 92b032378bSBartlomiej Zolnierkiewicz struct ahci_host_priv *hpriv = host->private_data; 93b032378bSBartlomiej Zolnierkiewicz struct device *dev = host->dev; 94a8237084SLee Jones struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); 95a8237084SLee Jones int err; 96a8237084SLee Jones 97a8237084SLee Jones if (drv_data->pwr) { 98a8237084SLee Jones err = reset_control_assert(drv_data->pwr); 99a8237084SLee Jones if (err) 10033081b34SBartlomiej Zolnierkiewicz dev_err(dev, "unable to pwrdwn\n"); 101a8237084SLee Jones } 102a8237084SLee Jones 103a8237084SLee Jones ahci_platform_disable_resources(hpriv); 104a8237084SLee Jones } 105a8237084SLee Jones 10676884cb2SLee Jones static int st_ahci_probe_resets(struct platform_device *pdev) 10776884cb2SLee Jones { 10876884cb2SLee Jones struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev); 10976884cb2SLee Jones 11076884cb2SLee Jones drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn"); 11176884cb2SLee Jones if (IS_ERR(drv_data->pwr)) { 11276884cb2SLee Jones dev_info(&pdev->dev, "power reset control not defined\n"); 11376884cb2SLee Jones drv_data->pwr = NULL; 11476884cb2SLee Jones } 11576884cb2SLee Jones 11676884cb2SLee Jones drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst"); 11776884cb2SLee Jones if (IS_ERR(drv_data->sw_rst)) { 11876884cb2SLee Jones dev_info(&pdev->dev, "soft reset control not defined\n"); 11976884cb2SLee Jones drv_data->sw_rst = NULL; 12076884cb2SLee Jones } 12176884cb2SLee Jones 12276884cb2SLee Jones drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst"); 12376884cb2SLee Jones if (IS_ERR(drv_data->pwr_rst)) { 12476884cb2SLee Jones dev_dbg(&pdev->dev, "power soft reset control not defined\n"); 12576884cb2SLee Jones drv_data->pwr_rst = NULL; 12676884cb2SLee Jones } 12776884cb2SLee Jones 12876884cb2SLee Jones return st_ahci_deassert_resets(&pdev->dev); 12976884cb2SLee Jones } 13076884cb2SLee Jones 131b032378bSBartlomiej Zolnierkiewicz static struct ata_port_operations st_ahci_port_ops = { 132b032378bSBartlomiej Zolnierkiewicz .inherits = &ahci_platform_ops, 133b032378bSBartlomiej Zolnierkiewicz .host_stop = st_ahci_host_stop, 134b032378bSBartlomiej Zolnierkiewicz }; 135b032378bSBartlomiej Zolnierkiewicz 13676884cb2SLee Jones static const struct ata_port_info st_ahci_port_info = { 13776884cb2SLee Jones .flags = AHCI_FLAG_COMMON, 13876884cb2SLee Jones .pio_mask = ATA_PIO4, 13976884cb2SLee Jones .udma_mask = ATA_UDMA6, 140b032378bSBartlomiej Zolnierkiewicz .port_ops = &st_ahci_port_ops, 14176884cb2SLee Jones }; 14276884cb2SLee Jones 143018d5ef2SAkinobu Mita static struct scsi_host_template ahci_platform_sht = { 144018d5ef2SAkinobu Mita AHCI_SHT(DRV_NAME), 145018d5ef2SAkinobu Mita }; 146018d5ef2SAkinobu Mita 14776884cb2SLee Jones static int st_ahci_probe(struct platform_device *pdev) 14876884cb2SLee Jones { 14976884cb2SLee Jones struct st_ahci_drv_data *drv_data; 15076884cb2SLee Jones struct ahci_host_priv *hpriv; 15176884cb2SLee Jones int err; 15276884cb2SLee Jones 15376884cb2SLee Jones drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL); 15476884cb2SLee Jones if (!drv_data) 15576884cb2SLee Jones return -ENOMEM; 15676884cb2SLee Jones 15776884cb2SLee Jones platform_set_drvdata(pdev, drv_data); 15876884cb2SLee Jones 15976884cb2SLee Jones hpriv = ahci_platform_get_resources(pdev); 16076884cb2SLee Jones if (IS_ERR(hpriv)) 16176884cb2SLee Jones return PTR_ERR(hpriv); 16276884cb2SLee Jones 16376884cb2SLee Jones drv_data->hpriv = hpriv; 16476884cb2SLee Jones 16576884cb2SLee Jones err = st_ahci_probe_resets(pdev); 16676884cb2SLee Jones if (err) 16776884cb2SLee Jones return err; 16876884cb2SLee Jones 16976884cb2SLee Jones err = ahci_platform_enable_resources(hpriv); 17076884cb2SLee Jones if (err) 17176884cb2SLee Jones return err; 17276884cb2SLee Jones 1739a1e75e1SPeter Griffin st_ahci_configure_oob(drv_data->hpriv->mmio); 1749a1e75e1SPeter Griffin 175018d5ef2SAkinobu Mita err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 176018d5ef2SAkinobu Mita &ahci_platform_sht); 17776884cb2SLee Jones if (err) { 17876884cb2SLee Jones ahci_platform_disable_resources(hpriv); 17976884cb2SLee Jones return err; 18076884cb2SLee Jones } 18176884cb2SLee Jones 18276884cb2SLee Jones return 0; 18376884cb2SLee Jones } 18476884cb2SLee Jones 18576884cb2SLee Jones #ifdef CONFIG_PM_SLEEP 18676884cb2SLee Jones static int st_ahci_suspend(struct device *dev) 18776884cb2SLee Jones { 18876884cb2SLee Jones struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); 18976884cb2SLee Jones struct ahci_host_priv *hpriv = drv_data->hpriv; 19076884cb2SLee Jones int err; 19176884cb2SLee Jones 19233081b34SBartlomiej Zolnierkiewicz err = ahci_platform_suspend_host(dev); 19333081b34SBartlomiej Zolnierkiewicz if (err) 19433081b34SBartlomiej Zolnierkiewicz return err; 195761a8c27SLee Jones 19676884cb2SLee Jones if (drv_data->pwr) { 19776884cb2SLee Jones err = reset_control_assert(drv_data->pwr); 19876884cb2SLee Jones if (err) { 19976884cb2SLee Jones dev_err(dev, "unable to pwrdwn"); 20076884cb2SLee Jones return err; 20176884cb2SLee Jones } 20276884cb2SLee Jones } 20376884cb2SLee Jones 20476884cb2SLee Jones ahci_platform_disable_resources(hpriv); 20576884cb2SLee Jones 20676884cb2SLee Jones return 0; 20776884cb2SLee Jones } 20876884cb2SLee Jones 20976884cb2SLee Jones static int st_ahci_resume(struct device *dev) 21076884cb2SLee Jones { 21176884cb2SLee Jones struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); 21276884cb2SLee Jones struct ahci_host_priv *hpriv = drv_data->hpriv; 21376884cb2SLee Jones int err; 21476884cb2SLee Jones 21576884cb2SLee Jones err = ahci_platform_enable_resources(hpriv); 21676884cb2SLee Jones if (err) 21776884cb2SLee Jones return err; 21876884cb2SLee Jones 21976884cb2SLee Jones err = st_ahci_deassert_resets(dev); 22076884cb2SLee Jones if (err) { 22176884cb2SLee Jones ahci_platform_disable_resources(hpriv); 22276884cb2SLee Jones return err; 22376884cb2SLee Jones } 22476884cb2SLee Jones 2259a1e75e1SPeter Griffin st_ahci_configure_oob(drv_data->hpriv->mmio); 2269a1e75e1SPeter Griffin 227761a8c27SLee Jones return ahci_platform_resume_host(dev); 22876884cb2SLee Jones } 22976884cb2SLee Jones #endif 23076884cb2SLee Jones 23176884cb2SLee Jones static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume); 23276884cb2SLee Jones 23309de99dbSKiran Padwal static const struct of_device_id st_ahci_match[] = { 23476884cb2SLee Jones { .compatible = "st,ahci", }, 23576884cb2SLee Jones {}, 23676884cb2SLee Jones }; 23776884cb2SLee Jones MODULE_DEVICE_TABLE(of, st_ahci_match); 23876884cb2SLee Jones 23976884cb2SLee Jones static struct platform_driver st_ahci_driver = { 24076884cb2SLee Jones .driver = { 241018d5ef2SAkinobu Mita .name = DRV_NAME, 24276884cb2SLee Jones .pm = &st_ahci_pm_ops, 24376884cb2SLee Jones .of_match_table = of_match_ptr(st_ahci_match), 24476884cb2SLee Jones }, 24576884cb2SLee Jones .probe = st_ahci_probe, 246a8237084SLee Jones .remove = ata_platform_remove_one, 24776884cb2SLee Jones }; 24876884cb2SLee Jones module_platform_driver(st_ahci_driver); 24976884cb2SLee Jones 25076884cb2SLee Jones MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>"); 25176884cb2SLee Jones MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>"); 2524a2e5123SLee Jones MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver"); 25376884cb2SLee Jones MODULE_LICENSE("GPL v2"); 254