162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Marvell 88SE64xx/88SE94xx register IO interface
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2007 Red Hat, Inc.
662306a36Sopenharmony_ci * Copyright 2008 Marvell. <kewei@marvell.com>
762306a36Sopenharmony_ci * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
862306a36Sopenharmony_ci*/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#ifndef _MV_CHIPS_H_
1262306a36Sopenharmony_ci#define _MV_CHIPS_H_
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define mr32(reg)	readl(regs + reg)
1562306a36Sopenharmony_ci#define mw32(reg, val)	writel((val), regs + reg)
1662306a36Sopenharmony_ci#define mw32_f(reg, val)	do {			\
1762306a36Sopenharmony_ci				mw32(reg, val);	\
1862306a36Sopenharmony_ci				mr32(reg);	\
1962306a36Sopenharmony_ci			} while (0)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define iow32(reg, val) 	outl(val, (unsigned long)(regs + reg))
2262306a36Sopenharmony_ci#define ior32(reg) 		inl((unsigned long)(regs + reg))
2362306a36Sopenharmony_ci#define iow16(reg, val) 	outw((unsigned long)(val, regs + reg))
2462306a36Sopenharmony_ci#define ior16(reg) 		inw((unsigned long)(regs + reg))
2562306a36Sopenharmony_ci#define iow8(reg, val) 		outb((unsigned long)(val, regs + reg))
2662306a36Sopenharmony_ci#define ior8(reg) 		inb((unsigned long)(regs + reg))
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic inline u32 mvs_cr32(struct mvs_info *mvi, u32 addr)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
3162306a36Sopenharmony_ci	mw32(MVS_CMD_ADDR, addr);
3262306a36Sopenharmony_ci	return mr32(MVS_CMD_DATA);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic inline void mvs_cw32(struct mvs_info *mvi, u32 addr, u32 val)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
3862306a36Sopenharmony_ci	mw32(MVS_CMD_ADDR, addr);
3962306a36Sopenharmony_ci	mw32(MVS_CMD_DATA, val);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
4562306a36Sopenharmony_ci	return (port < 4) ? mr32(MVS_P0_SER_CTLSTAT + port * 4) :
4662306a36Sopenharmony_ci		mr32(MVS_P4_SER_CTLSTAT + (port - 4) * 4);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
5262306a36Sopenharmony_ci	if (port < 4)
5362306a36Sopenharmony_ci		mw32(MVS_P0_SER_CTLSTAT + port * 4, val);
5462306a36Sopenharmony_ci	else
5562306a36Sopenharmony_ci		mw32(MVS_P4_SER_CTLSTAT + (port - 4) * 4, val);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic inline u32 mvs_read_port(struct mvs_info *mvi, u32 off,
5962306a36Sopenharmony_ci				u32 off2, u32 port)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	void __iomem *regs = mvi->regs + off;
6262306a36Sopenharmony_ci	void __iomem *regs2 = mvi->regs + off2;
6362306a36Sopenharmony_ci	return (port < 4) ? readl(regs + port * 8) :
6462306a36Sopenharmony_ci		readl(regs2 + (port - 4) * 8);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
6862306a36Sopenharmony_ci				u32 port, u32 val)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	void __iomem *regs = mvi->regs + off;
7162306a36Sopenharmony_ci	void __iomem *regs2 = mvi->regs + off2;
7262306a36Sopenharmony_ci	if (port < 4)
7362306a36Sopenharmony_ci		writel(val, regs + port * 8);
7462306a36Sopenharmony_ci	else
7562306a36Sopenharmony_ci		writel(val, regs2 + (port - 4) * 8);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	return mvs_read_port(mvi, MVS_P0_CFG_DATA,
8162306a36Sopenharmony_ci			MVS_P4_CFG_DATA, port);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic inline void mvs_write_port_cfg_data(struct mvs_info *mvi,
8562306a36Sopenharmony_ci						u32 port, u32 val)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	mvs_write_port(mvi, MVS_P0_CFG_DATA,
8862306a36Sopenharmony_ci			MVS_P4_CFG_DATA, port, val);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic inline void mvs_write_port_cfg_addr(struct mvs_info *mvi,
9262306a36Sopenharmony_ci						u32 port, u32 addr)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	mvs_write_port(mvi, MVS_P0_CFG_ADDR,
9562306a36Sopenharmony_ci			MVS_P4_CFG_ADDR, port, addr);
9662306a36Sopenharmony_ci	mdelay(10);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	return mvs_read_port(mvi, MVS_P0_VSR_DATA,
10262306a36Sopenharmony_ci			MVS_P4_VSR_DATA, port);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline void mvs_write_port_vsr_data(struct mvs_info *mvi,
10662306a36Sopenharmony_ci						u32 port, u32 val)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	mvs_write_port(mvi, MVS_P0_VSR_DATA,
10962306a36Sopenharmony_ci			MVS_P4_VSR_DATA, port, val);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic inline void mvs_write_port_vsr_addr(struct mvs_info *mvi,
11362306a36Sopenharmony_ci						u32 port, u32 addr)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	mvs_write_port(mvi, MVS_P0_VSR_ADDR,
11662306a36Sopenharmony_ci			MVS_P4_VSR_ADDR, port, addr);
11762306a36Sopenharmony_ci	mdelay(10);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	return mvs_read_port(mvi, MVS_P0_INT_STAT,
12362306a36Sopenharmony_ci			MVS_P4_INT_STAT, port);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline void mvs_write_port_irq_stat(struct mvs_info *mvi,
12762306a36Sopenharmony_ci						u32 port, u32 val)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	mvs_write_port(mvi, MVS_P0_INT_STAT,
13062306a36Sopenharmony_ci			MVS_P4_INT_STAT, port, val);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	return mvs_read_port(mvi, MVS_P0_INT_MASK,
13662306a36Sopenharmony_ci			MVS_P4_INT_MASK, port);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic inline void mvs_write_port_irq_mask(struct mvs_info *mvi,
14162306a36Sopenharmony_ci						u32 port, u32 val)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	mvs_write_port(mvi, MVS_P0_INT_MASK,
14462306a36Sopenharmony_ci			MVS_P4_INT_MASK, port, val);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic inline void mvs_phy_hacks(struct mvs_info *mvi)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	u32 tmp;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
15262306a36Sopenharmony_ci	tmp &= ~(1 << 9);
15362306a36Sopenharmony_ci	tmp |= (1 << 10);
15462306a36Sopenharmony_ci	mvs_cw32(mvi, CMD_PHY_TIMER, tmp);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* enable retry 127 times */
15762306a36Sopenharmony_ci	mvs_cw32(mvi, CMD_SAS_CTL1, 0x7f7f);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* extend open frame timeout to max */
16062306a36Sopenharmony_ci	tmp = mvs_cr32(mvi, CMD_SAS_CTL0);
16162306a36Sopenharmony_ci	tmp &= ~0xffff;
16262306a36Sopenharmony_ci	tmp |= 0x3fff;
16362306a36Sopenharmony_ci	mvs_cw32(mvi, CMD_SAS_CTL0, tmp);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* not to halt for different port op during wideport link change */
16862306a36Sopenharmony_ci	mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic inline void mvs_int_sata(struct mvs_info *mvi)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	u32 tmp;
17462306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
17562306a36Sopenharmony_ci	tmp = mr32(MVS_INT_STAT_SRS_0);
17662306a36Sopenharmony_ci	if (tmp)
17762306a36Sopenharmony_ci		mw32(MVS_INT_STAT_SRS_0, tmp);
17862306a36Sopenharmony_ci	MVS_CHIP_DISP->clear_active_cmds(mvi);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic inline void mvs_int_full(struct mvs_info *mvi)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
18462306a36Sopenharmony_ci	u32 tmp, stat;
18562306a36Sopenharmony_ci	int i;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	stat = mr32(MVS_INT_STAT);
18862306a36Sopenharmony_ci	mvs_int_rx(mvi, false);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	for (i = 0; i < mvi->chip->n_phy; i++) {
19162306a36Sopenharmony_ci		tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
19262306a36Sopenharmony_ci		if (tmp)
19362306a36Sopenharmony_ci			mvs_int_port(mvi, i, tmp);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (stat & CINT_NON_SPEC_NCQ_ERROR)
19762306a36Sopenharmony_ci		MVS_CHIP_DISP->non_spec_ncq_error(mvi);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (stat & CINT_SRS)
20062306a36Sopenharmony_ci		mvs_int_sata(mvi);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	mw32(MVS_INT_STAT, stat);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic inline void mvs_start_delivery(struct mvs_info *mvi, u32 tx)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
20862306a36Sopenharmony_ci	mw32(MVS_TX_PROD_IDX, tx);
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic inline u32 mvs_rx_update(struct mvs_info *mvi)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	void __iomem *regs = mvi->regs;
21462306a36Sopenharmony_ci	return mr32(MVS_RX_CONS_IDX);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic inline u32 mvs_get_prd_size(void)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	return sizeof(struct mvs_prd);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic inline u32 mvs_get_prd_count(void)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	return MAX_SG_ENTRY;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic inline void mvs_show_pcie_usage(struct mvs_info *mvi)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	u16 link_stat, link_spd;
23062306a36Sopenharmony_ci	const char *spd[] = {
23162306a36Sopenharmony_ci		"UnKnown",
23262306a36Sopenharmony_ci		"2.5",
23362306a36Sopenharmony_ci		"5.0",
23462306a36Sopenharmony_ci	};
23562306a36Sopenharmony_ci	if (mvi->flags & MVF_FLAG_SOC || mvi->id > 0)
23662306a36Sopenharmony_ci		return;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	pci_read_config_word(mvi->pdev, PCR_LINK_STAT, &link_stat);
23962306a36Sopenharmony_ci	link_spd = (link_stat & PLS_LINK_SPD) >> PLS_LINK_SPD_OFFS;
24062306a36Sopenharmony_ci	if (link_spd >= 3)
24162306a36Sopenharmony_ci		link_spd = 0;
24262306a36Sopenharmony_ci	dev_printk(KERN_INFO, mvi->dev,
24362306a36Sopenharmony_ci		"mvsas: PCI-E x%u, Bandwidth Usage: %s Gbps\n",
24462306a36Sopenharmony_ci	       (link_stat & PLS_NEG_LINK_WD) >> PLS_NEG_LINK_WD_OFFS,
24562306a36Sopenharmony_ci	       spd[link_spd]);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic inline u32 mvs_hw_max_link_rate(void)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	return MAX_LINK_RATE;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci#endif  /* _MV_CHIPS_H_ */
25462306a36Sopenharmony_ci
255