sata_sx4.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,500 行 · 第 1/3 页
C
1,500 行
(long) (window_size - offset); memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) 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((char *) (dimm_mmio), (char *) 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((char *) (dimm_mmio), (char *) psource, size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); }}static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata){ void *mmio = pe->mmio_base; 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_OFFSET); readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); /* Write Control to perform read operation, mask int */ writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, mmio + PDC_I2C_CONTROL_OFFSET); for (count = 0; count <= 1000; count ++) { status = readl(mmio + PDC_I2C_CONTROL_OFFSET); if (status & PDC_I2C_COMPLETE) { status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); break; } else if (count == 1000) return 0; } *pdata = (status >> 8) & 0x000000ff; return 1; }static int pdc20621_detect_dimm(struct ata_probe_ent *pe){ u32 data=0 ; if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_SYSTEM_FREQ, &data)) { if (data == 100) return 100; } else return 0; if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) { if(data <= 0x75) return 133; } else return 0; return 0;}static int pdc20621_prog_dimm0(struct ata_probe_ent *pe){ u32 spd0[50]; u32 data = 0; int size, i; u8 bdimmsize; void *mmio = pe->mmio_base; 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(pe, 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_OFFSET); readl(mmio + PDC_DIMM0_CONTROL_OFFSET); return size; }static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe){ u32 data, spd0; int error, i; void *mmio = pe->mmio_base; /* 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_OFFSET); readl(mmio + PDC_SDRAM_CONTROL_OFFSET); /* Turn on for ECC */ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { data |= (0x01 << 16); writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); readl(mmio + PDC_SDRAM_CONTROL_OFFSET); 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_OFFSET); error = 1; for (i = 1; i <= 10; i++) { /* polling ~5 secs */ data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET); if (!(data & (1<<19))) { error = 0; break; } set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((i * 100) * HZ / 1000 + 1); } return error;} static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe){ 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 *mmio = pe->mmio_base; /* 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(0x00001a0, mmio + PDC_TIME_CONTROL); readl(mmio + PDC_TIME_CONTROL); /* Wait 3 seconds */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(3 * HZ); /* 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(pe))) { 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(pe); VPRINTK("Local DIMM Size = %dMB\n",size); /* Programming DIMM Module Global Control Register (index_CID0:88h) */ if (pdc20621_prog_dimm_global(pe)) { 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(pe, (void *) test_parttern2, 0x10040, 40); pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40); pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40); pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 40); printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40); pdc20621_get_from_dimm(pe, (void *) 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(pe, 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(pe, (void *) &tmp, addr, sizeof(u32)); addr += sizeof(u32); } VPRINTK("Finish ECC initialization\n"); } return 0;}static void pdc_20621_init(struct ata_probe_ent *pe){ u32 tmp; void *mmio = pe->mmio_base; /* 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; struct ata_probe_ent *probe_ent = NULL; unsigned long base; void *mmio_base, *dimm_mmio = NULL; struct pdc_host_priv *hpriv = NULL; unsigned int board_idx = (unsigned int) ent->driver_data; int rc; if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then * we should check that here as it has a normal Serverworks ID */ rc = pci_enable_device(pdev); if (rc) return rc; rc = pci_request_regions(pdev, DRV_NAME); if (rc) goto err_out; rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { rc = -ENOMEM; goto err_out_regions; } memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->pdev = pdev; INIT_LIST_HEAD(&probe_ent->node); mmio_base = ioremap(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; } base = (unsigned long) mmio_base; hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); if (!hpriv) { rc = -ENOMEM; goto err_out_iounmap; } memset(hpriv, 0, sizeof(*hpriv)); dimm_mmio = ioremap(pci_resource_start(pdev, 4), pci_resource_len(pdev, 4)); if (!dimm_mmio) { kfree(hpriv); rc = -ENOMEM; goto err_out_iounmap; } hpriv->dimm_mmio = dimm_mmio; probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; probe_ent->mmio_base = mmio_base; probe_ent->private_data = hpriv; base += PDC_CHIP0_OFS; probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); pdc_sata_setup_port(&probe_ent->port[1], base + 0x280); pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); pci_set_master(pdev); /* initialize adapter */ /* initialize local dimm */ if (pdc20621_dimm_init(probe_ent)) { rc = -ENOMEM; goto err_out_iounmap_dimm; } pdc_20621_init(probe_ent); /* FIXME: check ata_device_add return value */ ata_device_add(probe_ent); kfree(probe_ent); return 0;err_out_iounmap_dimm: /* only get to this label if 20621 */ kfree(hpriv); iounmap(dimm_mmio);err_out_iounmap: iounmap(mmio_base);err_out_free_ent: kfree(probe_ent);err_out_regions: pci_release_regions(pdev);err_out: pci_disable_device(pdev); return rc;}static int __init pdc_sata_init(void){ return pci_module_init(&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_init(pdc_sata_init);module_exit(pdc_sata_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?