linux_dsm_epyc7002/lib/synolib/syno_sata_signal_check.c
AuxXxilium 5fa3ea047a init: add dsm gpl source
Signed-off-by: AuxXxilium <info@auxxxilium.tech>
2024-07-05 18:00:04 +02:00

302 lines
9.0 KiB
C

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/pci.h>
MODULE_LICENSE("Proprietary");
#define SYNO_JMB585_PORT_NUM 5
#define SYNO_JMB582_PORT_NUM 2
const unsigned jmb_port_addr[3][SYNO_JMB585_PORT_NUM] = {{0x74, 0x76, 0x78, 0x7A, 0x7C},
{0x73, 0x75, 0x77, 0x79, 0x7B},
{0x04, 0x11, 0x1e, 0x2b, 0x38}};
const unsigned jmb_port_ctle_reg[SYNO_JMB585_PORT_NUM] = {0x0B, 0x18, 0x25, 0x32, 0x3F};
const unsigned jmb_ssc_addr = 0x2;
static void syno_jmb_read_phy_reg(void __iomem *bar5, u32 addr, u32 *data, unsigned long reg_type)
{
// Index port has 24 bits, PHY registers access uses bit[12:0] and bit[18], bit[18] is used to select:
// 0: PCIe PHY registers.
// 1: SATA PHY registers.
// Offset C0 [IDXP] is index port register
writel((addr & 0x01FFFUL) + (reg_type << 18UL), bar5 + 0xC0);
// Offset C8 [DPHY] is data port for PCIe/SATA PHY registers access.
*data = readl(bar5 + 0xC8);
}
static int syno_jmb_sata_check(unsigned pID, int portNum)
{
struct pci_dev *pdev = NULL;
void __iomem *bar5 = NULL;
u32 value = 0;
int i = 0;
int j = 0;
int iRet = -1;
unsigned long reg_type = 0; //read sata register or pcie register, 1 for sata, 0 for pcie
printk("======= JMicron %x =======\n", pID);
while ((pdev = pci_get_device(0x197b, pID, pdev)) != NULL) {
bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5));
if (!bar5) {
printk("Can't map jmb%x registers pci%d:%d\n", pID, pdev->bus->number, pdev->bus->primary);
goto END;
}
//check pcie register
reg_type = 0; // 0 for pcie phy register
syno_jmb_read_phy_reg(bar5, 0x1035, &value, reg_type);// 0x00000001 1: enable, 0: disable
printk("pci %d:%d Preset %s\n", pdev->bus->number, pdev->bus->primary, (value & 0x00000001)?"Enable":"Disable");
syno_jmb_read_phy_reg(bar5, 0x1034, &value, reg_type);// 0x00000044 preset value, lane0/1 preset = 0x4
printk("pci %d:%d Preset Value: 0x%x\n", pdev->bus->number, pdev->bus->primary, value);
syno_jmb_read_phy_reg(bar5, 0x28, &value, reg_type); // 0x222A90F3 // PCIe impedance
printk("pci %d:%d PCIe impedance reg: 0x%x\n", pdev->bus->number, pdev->bus->primary, value);
syno_jmb_read_phy_reg(bar5, 0x428, &value, reg_type); // 0x222A90F3 // PCIe impedance
printk("pci %d:%d PCIe impedance reg: 0x%x\n", pdev->bus->number, pdev->bus->primary, value);
//check sata register
reg_type = 1; // 1 for sata phy register
syno_jmb_read_phy_reg(bar5, jmb_ssc_addr, &value, reg_type); //
printk("pci %d:%d SSC reg: 0x%x, SSC %s\n", pdev->bus->number, pdev->bus->primary, value, (value & 0x00000010)?"off":"on");
//check sata signal
for (i = 0 ; i < portNum; i++) {
for (j = 0 ; j < 3; j++) {
syno_jmb_read_phy_reg(bar5, jmb_port_addr[j][i], &value, reg_type);
printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1, value);
}
syno_jmb_read_phy_reg(bar5, jmb_port_ctle_reg[i], &value, reg_type);
printk("pci %d:%d port %d SATA CTLE : 0x%x\n",pdev->bus->number, pdev->bus->primary, i, value);
}
if (bar5) {
iounmap(bar5);
bar5 = NULL;
}
}
printk("============================\n");
iRet = 0;
END:
return iRet;
}
const unsigned mv_port_gen[3] = {0x8D, 0x8F, 0x91};
const unsigned mv_port_addr[4] = {0x178, 0x1f8, 0x278, 0x2f8};
const unsigned mv_port_data[4] = {0x17c, 0x1fc, 0x27c, 0x2fc};
static int syno_mv_sata_check(unsigned pID, int portNum)
{
struct pci_dev *pdev = NULL;
void __iomem *bar5 = NULL;
u32 value = 0;
int i = 0;
int j = 0;
int iRet = -1;
printk("======= Marvell %x =======\n", pID);
while ((pdev = pci_get_device(0x1b4b, pID, pdev)) != NULL) {
bar5 = ioremap(pci_resource_start(pdev, 5), pci_resource_len(pdev, 5));
if (!bar5) {
printk("Can't map mv%x registers pci%d:%d\n", pID, pdev->bus->number, pdev->bus->primary);
goto END;
}
for (i = 0 ; i < portNum; i++) {
for (j = 0; j < 3; j++) {
writel(mv_port_gen[j], bar5 + mv_port_addr[i]);
value = readl(bar5 + mv_port_data[i]);
printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1 ,value);
}
}
if (bar5) {
iounmap(bar5);
bar5 = NULL;
}
}
printk("============================\n");
iRet = 0;
END:
return iRet;
}
const unsigned asmedia_1061_gen[3] = {0x4, 0x5, 0x6};
const unsigned asmedia_1061_addr[2] = {0xCA0, 0xDA0};
const unsigned asmedia_116x_port_addr[3][6] = {{0x122, 0x322, 0x522, 0x722, 0x922, 0xB22},
{0x123, 0x323, 0x523, 0x723, 0x923, 0xB23},
{0x124, 0x324, 0x524, 0x724, 0x924, 0xB24}};
const unsigned asmedia_116x_ssc_addr = 0x198C;
static int syno_asm1061_sata_check(unsigned pID, int portNum)
{
struct pci_dev *pdev = NULL;
u8 value = 0;
unsigned int devfn = 0;
int i = 0;
int j = 0;
int iRet = -1;
devfn = PCI_DEVFN(0x00, 0x0);
printk("======= Asmedia 1061 =======\n");
while ((pdev = pci_get_device(0x1b21, pID, pdev)) != NULL) {
for (i = 0 ; i < portNum; i++) {
for (j = 0; j < 3; j++) {
pci_bus_read_config_byte(pdev->bus, devfn, asmedia_1061_addr[i] | asmedia_1061_gen[j], &value);
printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1 ,value);
}
}
}
printk("============================\n");
iRet = 0;
return iRet;
}
static int syno_asm116x_sata_check(unsigned pID,int portNum)
{
struct pci_dev *pdev = NULL;
void __iomem *bar0 = NULL;
u8 reg_data = 0;
int i = 0;
int j = 0;
int iRet = -1;
printk("======= Asmedia %x =======\n", pID);
while ((pdev = pci_get_device(0x1b21, pID, pdev)) != NULL) {
bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
if (!bar0) {
printk("Can't map asm%x registers pci%d:%d\n", pID, pdev->bus->number, pdev->bus->primary);
goto END;
}
//read SSC register
reg_data = readb(bar0 + asmedia_116x_ssc_addr);
printk("pci %d:%d SSC reg: 0x%x, SSC %s\n", pdev->bus->number, pdev->bus->primary, reg_data, (reg_data & 0x01)?"on":"off");
for (i = 0 ; i < portNum; i++) {
for (j = 0; j < 3; j++) {
reg_data = readb(bar0 + asmedia_116x_port_addr[j][i]);
printk("pci %d:%d port %d gen %d: %x\n",pdev->bus->number, pdev->bus->primary, i, j + 1 ,reg_data);
}
}
if (bar0) {
iounmap(bar0);
bar0 = NULL;
}
}
printk("============================\n");
iRet = 0;
END:
return iRet;
}
typedef union u {
u32 raw;
struct u_fields{
u8 byteen ;
u8 Register ;
u8 portid ;
u8 opcode ;
} field;
} SideBandMsg_t ;
#define UNCORE_REG_MCR 0xd0 // Message Control
#define UNCORE_REG_MDR 0xd4 // Message Data
#define UNCORE_REG_MER 0xd8 // Extended address or offset attributes
int MsgPortRead(u8 Opcode, u8 Port, u32 Register, u32 *Data, u32 addr)
{
SideBandMsg_t readMsg;
u32 Data32;
Data32= Register & 0xFFFFFF00;
readMsg.field.opcode = (u8) Opcode;
readMsg.field.portid = (u8) Port;
readMsg.field.byteen = (u8) 0xf0;
if( Register > 255 ) { // needs other register to hold 8+ bits
outl(addr + UNCORE_REG_MER, 0xCF8);
outl(Data32, 0xCFC);
readMsg.field.Register = (u8) Register ;
}else {
outl(addr + UNCORE_REG_MER, 0xCF8);
outl(0, 0xCFC);
readMsg.field.Register = (u8) Register ;
};
outl(addr + UNCORE_REG_MCR, 0xCF8);
outl(readMsg.raw, 0xCFC);
outl(addr + UNCORE_REG_MDR, 0xCF8);
*Data = inl(0xCFC);
return 0;
}
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
| (devfn << 8) | (reg & 0xFC))
static int intel_soc_sata(unsigned pID)
{
struct pci_dev *pdev = NULL;
u32 value = 0;
int i = 0;
int j = 0;
u32 offset_t = 0;
unsigned int port[4]= {0x0, 0x200, 0x400, 0x600};
unsigned int offset[6]= {0x88, 0x8c, 0x90, 0x100, 0x104, 0x108};
u32 addr = 0;
printk("======= Intel SoC SATA =======\n");
while ((pdev = pci_get_device(0x8086, pID, pdev)) != NULL) {
addr = PCI_CONF1_ADDRESS(0, pdev->devfn, 0);
for (i = 0 ; i < 2; i++) {
for (j = 0; j < 6; j++) {
offset_t = port[i] + offset[j];
MsgPortRead(0x0, 0x46, offset_t, &value, addr);
printk("gen3 port[%x] offset[%x]=0x%x\n", i, j, value);
}
printk("\n");
}
for (i = 0 ; i < 4; i++) {
for (j = 0; j < 6 ; j++) {
offset_t = port[i] + offset[j];
MsgPortRead(0x0, 0x43, offset_t, &value, addr);
printk("gen2 port[%x] offset[%x]=0x%x\n", i, j, value);
}
printk("\n");
}
}
return 0;
}
static int __init syno_sata_check_init(void)
{
syno_mv_sata_check(0x9235, 4);
syno_mv_sata_check(0x9215, 4);
syno_mv_sata_check(0x9170, 2);
syno_asm1061_sata_check(0x0612, 2);
syno_asm116x_sata_check(0x1164, 4);
syno_jmb_sata_check(0x0585, SYNO_JMB585_PORT_NUM);
syno_jmb_sata_check(0x0582, SYNO_JMB582_PORT_NUM);
intel_soc_sata(0x1f0c);
printk("Syno_SATA_check: Initialization completed.\n");
return 0;
}
static void __exit syno_sata_check_exit(void)
{
return;
}
MODULE_AUTHOR("EricC");
MODULE_DESCRIPTION("Syno_SATA_check\n");
MODULE_LICENSE("Synology Inc.");
module_init(syno_sata_check_init);
module_exit(syno_sata_check_exit);