📄 sata_sx4.c
字号:
readl(mmio + PDC_DIMM_WINDOW_CTLR); memcpy_fromio((char *) psource, (char *) (dimm_mmio), window_size / 4); psource += window_size; size -= window_size; idx++; } if (size) { writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); memcpy_fromio((char *) psource, (char *) (dimm_mmio), size / 4); }}#endifstatic void pdc20621_put_to_dimm(struct ata_host *host, void *psource, u32 offset, u32 size){ u32 window_size; u16 idx; u8 page_mask; long dist; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; page_mask = 0x00; window_size = 0x2000 * 4; /* 32K byte uchar size */ idx = (u16) (offset / window_size); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); offset -= (idx * window_size); idx++; dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); memcpy_toio(dimm_mmio + offset / 4, psource, dist); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); psource += dist; size -= dist; for (; (long) size >= (long) window_size ;) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); memcpy_toio(dimm_mmio, psource, window_size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); psource += window_size; size -= window_size; idx++; } if (size) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); memcpy_toio(dimm_mmio, psource, size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); }}static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device, u32 subaddr, u32 *pdata){ void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; u32 i2creg = 0; u32 status; u32 count = 0; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; i2creg |= device << 24; i2creg |= subaddr << 16; /* Set the device and subaddress */ writel(i2creg, mmio + PDC_I2C_ADDR_DATA); readl(mmio + PDC_I2C_ADDR_DATA); /* Write Control to perform read operation, mask int */ writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, mmio + PDC_I2C_CONTROL); for (count = 0; count <= 1000; count ++) { status = readl(mmio + PDC_I2C_CONTROL); if (status & PDC_I2C_COMPLETE) { status = readl(mmio + PDC_I2C_ADDR_DATA); break; } else if (count == 1000) return 0; } *pdata = (status >> 8) & 0x000000ff; return 1;}static int pdc20621_detect_dimm(struct ata_host *host){ u32 data = 0; if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_SYSTEM_FREQ, &data)) { if (data == 100) return 100; } else return 0; if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) { if (data <= 0x75) return 133; } else return 0; return 0;}static int pdc20621_prog_dimm0(struct ata_host *host){ u32 spd0[50]; u32 data = 0; int size, i; u8 bdimmsize; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; static const struct { unsigned int reg; unsigned int ofs; } pdc_i2c_read_data [] = { { PDC_DIMM_SPD_TYPE, 11 }, { PDC_DIMM_SPD_FRESH_RATE, 12 }, { PDC_DIMM_SPD_COLUMN_NUM, 4 }, { PDC_DIMM_SPD_ATTRIBUTE, 21 }, { PDC_DIMM_SPD_ROW_NUM, 3 }, { PDC_DIMM_SPD_BANK_NUM, 17 }, { PDC_DIMM_SPD_MODULE_ROW, 5 }, { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 }, { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 }, { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 }, { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 }, { PDC_DIMM_SPD_CAS_LATENCY, 18 }, }; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; for (i = 0; i < ARRAY_SIZE(pdc_i2c_read_data); i++) pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, pdc_i2c_read_data[i].reg, &spd0[pdc_i2c_read_data[i].ofs]); data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4); data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | ((((spd0[27] + 9) / 10) - 1) << 8) ; data |= (((((spd0[29] > spd0[28]) ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12; if (spd0[18] & 0x08) data |= ((0x03) << 14); else if (spd0[18] & 0x04) data |= ((0x02) << 14); else if (spd0[18] & 0x01) data |= ((0x01) << 14); else data |= (0 << 14); /* Calculate the size of bDIMMSize (power of 2) and merge the DIMM size by program start/end address. */ bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3; size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */ data |= (((size / 16) - 1) << 16); data |= (0 << 23); data |= 8; writel(data, mmio + PDC_DIMM0_CONTROL); readl(mmio + PDC_DIMM0_CONTROL); return size;}static unsigned int pdc20621_prog_dimm_global(struct ata_host *host){ u32 data, spd0; int error, i; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; /* Set To Default : DIMM Module Global Control Register (0x022259F1) DIMM Arbitration Disable (bit 20) DIMM Data/Control Output Driving Selection (bit12 - bit15) Refresh Enable (bit 17) */ data = 0x022259F1; writel(data, mmio + PDC_SDRAM_CONTROL); readl(mmio + PDC_SDRAM_CONTROL); /* Turn on for ECC */ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { data |= (0x01 << 16); writel(data, mmio + PDC_SDRAM_CONTROL); readl(mmio + PDC_SDRAM_CONTROL); printk(KERN_ERR "Local DIMM ECC Enabled\n"); } /* DIMM Initialization Select/Enable (bit 18/19) */ data &= (~(1<<18)); data |= (1<<19); writel(data, mmio + PDC_SDRAM_CONTROL); error = 1; for (i = 1; i <= 10; i++) { /* polling ~5 secs */ data = readl(mmio + PDC_SDRAM_CONTROL); if (!(data & (1<<19))) { error = 0; break; } msleep(i*100); } return error;}static unsigned int pdc20621_dimm_init(struct ata_host *host){ int speed, size, length; u32 addr, spd0, pci_status; u32 tmp = 0; u32 time_period = 0; u32 tcount = 0; u32 ticks = 0; u32 clock = 0; u32 fparam = 0; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; /* Initialize PLL based upon PCI Bus Frequency */ /* Initialize Time Period Register */ writel(0xffffffff, mmio + PDC_TIME_PERIOD); time_period = readl(mmio + PDC_TIME_PERIOD); VPRINTK("Time Period Register (0x40): 0x%x\n", time_period); /* Enable timer */ writel(PDC_TIMER_DEFAULT, mmio + PDC_TIME_CONTROL); readl(mmio + PDC_TIME_CONTROL); /* Wait 3 seconds */ msleep(3000); /* When timer is enabled, counter is decreased every internal clock cycle. */ tcount = readl(mmio + PDC_TIME_COUNTER); VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount); /* If SX4 is on PCI-X bus, after 3 seconds, the timer counter register should be >= (0xffffffff - 3x10^8). */ if (tcount >= PCI_X_TCOUNT) { ticks = (time_period - tcount); VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks); clock = (ticks / 300000); VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock); clock = (clock * 33); VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock); /* PLL F Param (bit 22:16) */ fparam = (1400000 / clock) - 2; VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam); /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */ pci_status = (0x8a001824 | (fparam << 16)); } else pci_status = PCI_PLL_INIT; /* Initialize PLL. */ VPRINTK("pci_status: 0x%x\n", pci_status); writel(pci_status, mmio + PDC_CTL_STATUS); readl(mmio + PDC_CTL_STATUS); /* Read SPD of DIMM by I2C interface, and program the DIMM Module Controller. */ if (!(speed = pdc20621_detect_dimm(host))) { printk(KERN_ERR "Detect Local DIMM Fail\n"); return 1; /* DIMM error */ } VPRINTK("Local DIMM Speed = %d\n", speed); /* Programming DIMM0 Module Control Register (index_CID0:80h) */ size = pdc20621_prog_dimm0(host); VPRINTK("Local DIMM Size = %dMB\n", size); /* Programming DIMM Module Global Control Register (index_CID0:88h) */ if (pdc20621_prog_dimm_global(host)) { printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n"); return 1; }#ifdef ATA_VERBOSE_DEBUG { u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ', 'N','o','t',' ','Y','e','t',' ', 'D','e','f','i','n','e','d',' ', '1','.','1','0', '9','8','0','3','1','6','1','2',0,0}; u8 test_parttern2[40] = {0}; pdc20621_put_to_dimm(host, test_parttern2, 0x10040, 40); pdc20621_put_to_dimm(host, test_parttern2, 0x40, 40); pdc20621_put_to_dimm(host, test_parttern1, 0x10040, 40); pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); pdc20621_get_from_dimm(host, test_parttern2, 0x10040, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); pdc20621_put_to_dimm(host, test_parttern1, 0x40, 40); pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); }#endif /* ECC initiliazation. */ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { VPRINTK("Start ECC initialization\n"); addr = 0; length = size * 1024 * 1024; while (addr < length) { pdc20621_put_to_dimm(host, (void *) &tmp, addr, sizeof(u32)); addr += sizeof(u32); } VPRINTK("Finish ECC initialization\n"); } return 0;}static void pdc_20621_init(struct ata_host *host){ u32 tmp; void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; /* * Select page 0x40 for our 32k DIMM window */ tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000; tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */ writel(tmp, mmio + PDC_20621_DIMM_WINDOW); /* * Reset Host DMA */ tmp = readl(mmio + PDC_HDMA_CTLSTAT); tmp |= PDC_RESET; writel(tmp, mmio + PDC_HDMA_CTLSTAT); readl(mmio + PDC_HDMA_CTLSTAT); /* flush */ udelay(10); tmp = readl(mmio + PDC_HDMA_CTLSTAT); tmp &= ~PDC_RESET; writel(tmp, mmio + PDC_HDMA_CTLSTAT); readl(mmio + PDC_HDMA_CTLSTAT); /* flush */}static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ static int printed_version; const struct ata_port_info *ppi[] = { &pdc_port_info[ent->driver_data], NULL }; struct ata_host *host; struct pdc_host_priv *hpriv; int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); /* allocate host */ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4); hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); if (!host || !hpriv) return -ENOMEM; host->private_data = hpriv; /* acquire resources and fill host */ rc = pcim_enable_device(pdev); if (rc) return rc; rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR), DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); if (rc) return rc; host->iomap = pcim_iomap_table(pdev); for (i = 0; i < 4; i++) { struct ata_port *ap = host->ports[i]; void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; unsigned int offset = 0x200 + i * 0x80; pdc_sata_setup_port(&ap->ioaddr, base + offset); ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm"); ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port"); } /* configure and activate */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) return rc; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) return rc; if (pdc20621_dimm_init(host)) return -ENOMEM; pdc_20621_init(host); pci_set_master(pdev); return ata_host_activate(host, pdev->irq, pdc20621_interrupt, IRQF_SHARED, &pdc_sata_sht);}static int __init pdc_sata_init(void){ return pci_register_driver(&pdc_sata_pci_driver);}static void __exit pdc_sata_exit(void){ pci_unregister_driver(&pdc_sata_pci_driver);}MODULE_AUTHOR("Jeff Garzik");MODULE_DESCRIPTION("Promise SATA low-level driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);MODULE_VERSION(DRV_VERSION);module_init(pdc_sata_init);module_exit(pdc_sata_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -