tegrakernel/kernel/nvidia/drivers/ata/tegra/ahci_tegra.h

455 lines
13 KiB
C
Raw Permalink Normal View History

2022-02-16 09:13:02 -06:00
/*
* drivers/ata/ahci_tegra.h
*
* Copyright (c) 2015-2019, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _AHCI_TEGRA_H
#define _AHCI_TEGRA_H
#include <linux/ahci_platform.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <soc/tegra/pmc.h>
#include <soc/tegra/chip-id.h>
#include <linux/tegra_prod.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/of_gpio.h>
#include <ahci.h>
#define DRV_NAME "tegra_ahci"
/* AUX Registers */
#define SATA_AUX_RX_STAT_INT_0 0xc
#define SATA_DEVSLP BIT(7)
#define SATA_AUX_MISC_CNTL_1_0 0x8
#define DEVSLP_OVERRIDE BIT(17)
#define SDS_SUPPORT BIT(13)
#define DESO_SUPPORT BIT(15)
#define SATA_AUX_SPARE_CFG0_0 0x18
#define MDAT_TIMER_AFTER_PG_VALID BIT(14)
/* IPFS Register Space */
#define SATA_CONFIGURATION_0 0x180
#define SATA_CONFIGURATION_0_EN_FPCI BIT(0)
#define SATA_CONFIGURATION_CLK_OVERRIDE BIT(31)
#define SATA_FPCI_BAR5_0 0x94
#define FPCI_BAR5_START_MASK (0xFFFFFFF << 4)
#define FPCI_BAR5_START (0x0040020 << 4)
#define FPCI_BAR5_ACCESS_TYPE (0x1)
#define SATA_INTR_MASK_0 0x188
#define IP_INT_MASK BIT(16)
/* Configuration Register Space */
#define T_SATA_BKDOOR_CC 0x4A4
#define T_SATA_BKDOOR_CC_CLASS_CODE_MASK (0xFFFF << 16)
#define T_SATA_BKDOOR_CC_CLASS_CODE (0x0106 << 16)
#define T_SATA_BKDOOR_CC_PROG_IF_MASK (0xFF << 8)
#define T_SATA_BKDOOR_CC_PROG_IF (0x01 << 8)
#define T_SATA_CFG_SATA 0x54C
#define T_SATA_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12)
#define T_SATA_CHX_PHY_CTRL17 0x6E8
#define T_SATA_CHX_PHY_CTRL17_RX_EQ_CTRL_L_GEN1 0x55010000
#define T_SATA_CHX_PHY_CTRL18 0x6EC
#define T_SATA_CHX_PHY_CTRL18_RX_EQ_CTRL_L_GEN2 0x55010000
#define T_SATA_CHX_PHY_CTRL20 0x6F4
#define T_SATA_CHX_PHY_CTRL20_RX_EQ_CTRL_H_GEN1 0x01
#define T_SATA_CHX_PHY_CTRL21 0x6F8
#define T_SATA_CHX_PHY_CTRL21_RX_EQ_CTRL_H_GEN2 0x01
#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300
#define T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP BIT(13)
#define T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP BIT(14)
#define T_SATA0_AHCI_HBA_CAP_BKDR_SALP BIT(26)
#define T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM BIT(17)
#define T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ BIT(30)
#define T_SATA0_AHCI_HBA_CTL_0 0x30C
#define T_SATA0_AHCI_HBA_CTL_0_PSM2LL_DENY_PMREQ BIT(26)
#define T_SATA0_CFG_LINK_0 0x174
#define T_SATA0_CFG_LINK_0_WAIT_FOR_PSM_FOR_PMOFF BIT(20)
#define T_SATA_CFG_PHY_0 0x120
#define T_SATA_CFG_PHY_0_MASK_SQUELCH BIT(24)
#define T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD BIT(11)
#define T_SATA0_CFG_PHY_0_DONT_INSERT_ALIGNS_IN_BIST_L BIT(8)
#define T_SATA0_NVOOB 0x114
#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK (0x3 << 26)
#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH (0x3 << 26)
#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK (0x3 << 24)
#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE (0x1 << 24)
#define T_SATA_CFG_1 0x4
#define T_SATA_CFG_1_IO_SPACE BIT(0)
#define T_SATA_CFG_1_MEMORY_SPACE BIT(1)
#define T_SATA_CFG_1_BUS_MASTER BIT(2)
#define T_SATA_CFG_1_SERR BIT(8)
#define T_SATA_CFG_9 0x24
#define T_SATA_CFG_9_BASE_ADDRESS 0x40020000
#define T_SATA0_CFG_35 0x94
#define T_SATA0_CFG_35_IDP_INDEX_MASK (0x7FF << 2)
#define T_SATA0_CFG_35_IDP_INDEX (0x2A << 2)
#define T_SATA0_AHCI_IDP1 0x98
#define T_SATA0_AHCI_IDP1_DATA (0x400040)
#define T_SATA0_CFG_PHY_1 0x12C
#define T_SATA0_CFG_PHY_1_PADS_IDDQ_EN BIT(23)
#define T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN BIT(22)
#define T_SATA0_INDEX 0x680
#define T_SATA0_INDEX_NONE_SELECTED 0
#define T_SATA0_INDEX_CH1 BIT(0)
#define T_SATA0_CFG_POWER_GATE 0x4AC
#define T_SATA0_CFG_POWER_GATE_SSTS_RESTORED BIT(23)
#define T_SATA0_CFG_POWER_GATE_POWER_UNGATE_COMP BIT(1)
#define T_SATA0_CFG2NVOOB_2 0x134
#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK (0x1ff << 18)
#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW (0xc << 18)
#define T_SATA0_CFG_LINK_0 0x174
#define T_SATA0_CFG_LINK_0_USE_POSEDGE_SCTL_DET BIT(24)
#define T_SATA0_AHCI_HBA_BIST_DWORD 0x31c
#define T_SATA0_AHCI_HBA_BIST_DWORD_DATA 0x4a4a4a4a
#define T_SATA0_AHCI_HBA_BIST_DWORD_DATA_MFTP 0x78787878
#define T_SATA0_AHCI_HBA_BIST_DWORD_DATA_LFTP 0x7e7e7e7e
#define T_SATA0_AHCI_HBA_BIST_DWORD_DATA_LBP 0x0C8B0C6B
#define T_SATA0_AHCI_HBA_BIST_OVERRIDE_CTL 0x318
#define T_SATA0_AHCI_HBA_BIST_OVERRIDE_CTL_DATA1 0x00000680
#define T_SATA0_AHCI_HBA_BIST_OVERRIDE_CTL_DATA2 0xff000640
#define T_SATA0_AHCI_HBA_BIST_OVERRIDE_CTL_DATA3 0xff00062e
#define T_SATA0_SPARE_2 0x528
#define T_SATA0_SPARE_2_REM_TWO_ALIGNS_IN_BIST_L BIT(0)
#define T_SATA0_CHXCFG4_CHX 0x704
#define T_SATA0_CHXCFG4_CHX_DATA 0x0
/* AHCI registers */
#define T_AHCI_HBA_GHC 0x4
#define T_AHCI_HBA_GHC_HR BIT(0)
#define T_AHCI_HBA_GHC_AE BIT(31)
/* AHCI Port Registers */
#define T_AHCI_PORT_PXSSTS 0x128
#define T_AHCI_PORT_PXSSTS_IPM_MASK (0xF00)
#define T_AHCI_PORT_PXSSTS_IPM_SHIFT (8)
#define T_AHCI_PORT_PXCMD 0x118
#define T_AHCI_PORT_PXCMD_ICC_MASK (0xF << 28)
#define T_AHCI_PORT_PXCMD_ICC_ACTIVE (0x1 << 28)
#define T_AHCI_PORT_PXCMD_ICC_PARTIAL (0x2 << 28)
#define T_AHCI_PORT_PXCMD_ICC_SLUMBER (0x6 << 28)
#define T_AHCI_PORT_PXCMD_ICC_DEVSLEEP (0x8 << 28)
#define T_AHCI_PORT_PXCMD_ICC_TIMEOUT 10
#define TEGRA_SATA_CORE_CLOCK_FREQ_HZ (102*1000*1000)
#define TEGRA_SATA_OOB_CLOCK_FREQ_HZ (204*1000*1000)
/* PMC registers */
#define PMC_IMPL_SATA_PWRGT_0_PG_INFO BIT(6)
#define TEGRA_AHCI_MAX_CLKS 2
#define TEGRA_AHCI_LPM_TIMEOUT 500
#define TEGRA_AHCI_READ_LOG_EXT_NOENTRY 0x80
/* Badblock Management */
#define TEGRA_BADBLK_STRING_LENGTH 100
enum tegra_badblk_arguments {
TEGRA_BADBLK_COMMAND,
TEGRA_BADBLK_COMMAND_PARAM1,
TEGRA_BADBLK_COMMAND_PARAM2,
TEGRA_BADBLK_MAX_ARGUMENTS,
};
enum tegra_sata_bars {
TEGRA_SATA_IPFS = 0,
TEGRA_SATA_CONFIG,
TEGRA_SATA_AHCI,
TEGRA_SATA_AUX,
TEGRA_SATA_BARS_MAX,
};
enum tegra_ahci_port_runtime_status {
TEGRA_AHCI_PORT_RUNTIME_ACTIVE = 1,
TEGRA_AHCI_PORT_RUNTIME_PARTIAL = 2,
TEGRA_AHCI_PORT_RUNTIME_SLUMBER = 6,
TEGRA_AHCI_PORT_RUNTIME_DEVSLP = 8,
};
struct tegra_ahci_badblk_info {
unsigned long long block;
char block_dev[TEGRA_BADBLK_STRING_LENGTH];
struct tegra_ahci_badblk_info *next;
};
struct tegra_ahci_badblk_priv {
struct work_struct badblk_work;
struct tegra_ahci_badblk_info *head;
spinlock_t badblk_lock;
};
struct tegra_ahci_priv {
struct platform_device *pdev;
void __iomem *base_list[TEGRA_SATA_BARS_MAX];
struct resource *res[TEGRA_SATA_BARS_MAX];
struct regulator_bulk_data *supplies;
struct tegra_ahci_soc_data *soc_data;
void *pg_save;
struct reset_control *sata_rst;
struct reset_control *sata_cold_rst;
struct reset_control *sata_oob_rst;
struct clk *sata_clk;
struct clk *sata_oob_clk;
struct clk *pllp_clk; /* sata_oob clk parent */
struct clk *pllp_uphy_clk; /* sata_clk parent */
struct pinctrl *devslp_pin;
struct pinctrl_state *devslp_active;
struct pinctrl_state *devslp_pullup;
struct tegra_prod *prod_list;
struct delayed_work work;
struct tegra_ahci_badblk_priv badblk;
int devslp_gpio;
bool devslp_override;
bool devslp_pinmux_override;
bool skip_rtpm;
};
struct tegra_ahci_ops {
int (*tegra_ahci_power_on)(struct ahci_host_priv *);
void (*tegra_ahci_power_off)(struct ahci_host_priv *);
int (*tegra_ahci_quirks)(struct ahci_host_priv *);
int (*tegra_ahci_platform_get_resources)
(struct tegra_ahci_priv *);
};
struct tegra_ahci_soc_data {
char * const *sata_regulator_names;
int num_sata_regulators;
struct tegra_ahci_ops ops;
void *data;
struct reg {
u32 t_satao_nvoob_comma_cnt_mask;
u32 t_satao_nvoob_comma_cnt;
} reg;
int powergate_id;
bool enable_pose_edge;
};
#ifdef CONFIG_DEBUG_FS
int tegra_ahci_dbg_dump_show(struct seq_file *s, void *data);
int tegra_ahci_dump_debuginit(void *data);
#endif
#ifdef CONFIG_PM
#ifndef _AHCI_TEGRA_DEBUG_H
static u32 pg_save_bar5_registers[] = {
0x018, /* T_AHCI_HBA_CCC_PORTS */
0x004, /* T_AHCI_HBA_GHC */
0x014, /* T_AHCI_HBA_CCC_CTL - OP (optional) */
0x01C, /* T_AHCI_HBA_EM_LOC */
0x020 /* T_AHCI_HBA_EM_CTL - OP */
};
static u32 pg_save_bar5_port_registers[] = {
0x100, /* T_AHCI_PORT_PXCLB */
0x104, /* T_AHCI_PORT_PXCLBU */
0x108, /* T_AHCI_PORT_PXFB */
0x10C, /* T_AHCI_PORT_PXFBU */
0x114, /* T_AHCI_PORT_PXIE */
0x118, /* T_AHCI_PORT_PXCMD */
0x12C, /* T_AHCI_PORT_PXSCTL */
0x144 /* T_AHCI_PORT_PXDEVSLP */
};
/*
* pg_save_bar5_bkdr_registers:
* These registers in BAR5 are read only.
* To restore back those register values, write the saved value
* to the registers specified in pg_restore_bar5_bkdr_registers[].
* These pg_restore_bar5_bkdr_registers[] are in SATA_CONFIG space.
*/
static u32 pg_save_bar5_bkdr_registers[] = {
/* Save and restore via bkdr writes */
0x000, /* T_AHCI_HBA_CAP */
0x00C, /* T_AHCI_HBA_PI */
0x024 /* T_AHCI_HBA_CAP2 */
};
static u32 pg_restore_bar5_bkdr_registers[] = {
/* Save and restore via bkdr writes */
0x300, /* BKDR of T_AHCI_HBA_CAP */
0x33c, /* BKDR of T_AHCI_HBA_PI */
0x330 /* BKDR of T_AHCI_HBA_CAP2 */
};
/* These registers are saved for each port */
static u32 pg_save_bar5_bkdr_port_registers[] = {
0x120, /* NV_PROJ__SATA0_CHX_AHCI_PORT_PXTFD */
0x124, /* NV_PROJ__SATA0_CHX_AHCI_PORT_PXSIG */
0x128 /* NV_PROJ__SATA0_CHX_AHCI_PORT_PXSSTS */
};
static u32 pg_restore_bar5_bkdr_port_registers[] = {
/* Save and restore via bkdr writes */
0x790, /* BKDR of NV_PROJ__SATA0_CHX_AHCI_PORT_PXTFD */
0x794, /* BKDR of NV_PROJ__SATA0_CHX_AHCI_PORT_PXSIG */
0x798 /* BKDR of NV_PROJ__SATA0_CHX_AHCI_PORT_PXSSTS */
};
static inline void tegra_ahci_save_regs(u32 **save_addr,
void __iomem *reg_base,
u32 reg_array[],
u32 regs)
{
u32 i;
u32 *dest = *save_addr;
for (i = 0; i < regs; ++i, ++dest)
*dest = readl(reg_base + reg_array[i]);
*save_addr = dest;
}
static inline void tegra_ahci_restore_regs(void **save_addr,
void __iomem *reg_base,
u32 reg_array[],
u32 regs)
{
u32 i;
u32 *src = *save_addr;
for (i = 0; i < regs; ++i, ++src)
writel(*src, reg_base + reg_array[i]);
*save_addr = src;
}
#endif
#endif
static inline u32 tegra_ahci_bar5_readl(struct ahci_host_priv *hpriv,
u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
u32 rval = 0;
rval = readl(tegra->base_list[TEGRA_SATA_AHCI] + offset);
return rval;
}
static inline void tegra_ahci_bar5_update(struct ahci_host_priv *hpriv, u32 val,
u32 mask, u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
u32 rval = 0;
rval = readl(tegra->base_list[TEGRA_SATA_AHCI] + offset);
rval = (rval & ~mask) | (val & mask);
writel(rval, tegra->base_list[TEGRA_SATA_AHCI] + offset);
rval = readl(tegra->base_list[TEGRA_SATA_AHCI] + offset);
}
static inline void tegra_ahci_sata_update(struct ahci_host_priv *hpriv, u32 val,
u32 mask, u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
u32 rval = 0;
rval = readl(tegra->base_list[TEGRA_SATA_IPFS] + offset);
rval = (rval & ~mask) | (val & mask);
writel(rval, tegra->base_list[TEGRA_SATA_IPFS] + offset);
rval = readl(tegra->base_list[TEGRA_SATA_IPFS] + offset);
}
static inline void tegra_ahci_scfg_writel(struct ahci_host_priv *hpriv, u32 val,
u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
writel(val, tegra->base_list[TEGRA_SATA_CONFIG] + offset);
readl(tegra->base_list[TEGRA_SATA_CONFIG] + offset);
}
static inline u32 tegra_ahci_scfg_readl(struct ahci_host_priv *hpriv,
u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
u32 rval = 0;
rval = readl(tegra->base_list[TEGRA_SATA_CONFIG] + offset);
return rval;
}
static inline void tegra_ahci_scfg_update(struct ahci_host_priv *hpriv, u32 val,
u32 mask, u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
u32 rval = 0;
rval = readl(tegra->base_list[TEGRA_SATA_CONFIG] + offset);
rval = (rval & ~mask) | (val & mask);
writel(rval, tegra->base_list[TEGRA_SATA_CONFIG] + offset);
rval = readl(tegra->base_list[TEGRA_SATA_CONFIG] + offset);
}
static inline u32 tegra_ahci_aux_readl(struct ahci_host_priv *hpriv, u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
u32 rval = 0;
rval = readl(tegra->base_list[TEGRA_SATA_AUX] + offset);
return rval;
}
static inline void tegra_ahci_aux_update(struct ahci_host_priv *hpriv, u32 val,
u32 mask, u32 offset)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
u32 rval = 0;
rval = readl(tegra->base_list[TEGRA_SATA_AUX] + offset);
rval = (rval & ~mask) | (val & mask);
writel(rval, tegra->base_list[TEGRA_SATA_AUX] + offset);
rval = readl(tegra->base_list[TEGRA_SATA_AUX] + offset);
}
u64 tegra_ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
#endif