diff --git a/bcwc_hw.c b/bcwc_hw.c index 0d96c4d..2ee6b98 100644 --- a/bcwc_hw.c +++ b/bcwc_hw.c @@ -839,8 +839,150 @@ int bcwc_hw_verify_mem(struct bcwc_private *dev_priv, u32 base) /* FIXME: Make some more sense out of this */ static int bcwc_hw_ddr_calibrate_rd_data_dly_fifo(struct bcwc_private *dev_priv) { + u32 base = 0x2800; + u32 offset_1 = base + 0x200; + u32 offset_2 = base + 0x274; + u32 offset_3 = base + 0x314; + u32 delay_reg = base + 0x360; + u32 offset_5 = base + 0x390; + u32 offset_6 = base + 0x394; + u32 reg_saved_1, reg_saved_2, reg_saved_3; - return 0; + u32 a, b, c, d, r8, r12, r14, r15; + u32 var_2c, var_30, fifo_delay, var_38; + + int ret; + + /* Save current register values */ + reg_saved_1 = BCWC_S2_REG_READ(offset_1); + reg_saved_2 = BCWC_S2_REG_READ(offset_2); + reg_saved_3 = BCWC_S2_REG_READ(offset_3); + + BCWC_S2_REG_WRITE(0x30000, offset_1); + bcwc_hw_pci_post(dev_priv); + + BCWC_S2_REG_WRITE(0x30100, offset_2); + bcwc_hw_pci_post(dev_priv); + + BCWC_S2_REG_WRITE(0x30100, offset_3); + bcwc_hw_pci_post(dev_priv); + + fifo_delay = 1; + a = 1000; + r15 = 0; + b = 0; + var_30 = 0; + var_2c = 0; + + do { + var_38 = a; + + BCWC_S2_REG_WRITE((fifo_delay & 0x7), delay_reg); + bcwc_hw_pci_post(dev_priv); + + /* + * How do we know if verification was successful? + * OSX doesn't check any return values from it's verification so + * perhaps controller can detect this itself and set some regs. + */ + bcwc_hw_verify_mem(dev_priv, 0); + + BCWC_S2_REG_WRITE(1, offset_6); + bcwc_hw_pci_post(dev_priv); + + r8 = (b >= 57) ? b : (b + 7); + + a = r15 + 7; + b = a; + if (b < 57) + b = r15; + + if (b > 63) { + a = 1; + b = 0; + r8 = 0; + } + + c = var_38 - 1; + + r14 = (BCWC_S2_REG_READ(offset_5) & 0xf) | var_2c; + if (r14 == 0) + var_2c = fifo_delay; + if (var_2c == 0) + c = 1; + + r12 = (BCWC_S2_REG_READ(offset_5) & 0xf0) | var_30; + if (r12 == 0) + var_30 = fifo_delay; + if (var_30 == 0) + d = 1; + + a += fifo_delay; + if (a < 8) { + r15 = (c | d) ^ 1; + fifo_delay = a; + } else { + if (var_30 == 0) + var_30 = 7; + if (var_2c == 0) + var_2c = 7; + fifo_delay = 7; + r15 = 1; + } + + BCWC_S2_REG_WRITE((r8 & 0x3f) | 0x30000, offset_1); + bcwc_hw_pci_post(dev_priv); + + BCWC_S2_REG_WRITE((b & 0x3f) | 0x30100, offset_2); + bcwc_hw_pci_post(dev_priv); + + BCWC_S2_REG_WRITE((b & 0x3f) | 0x30100, offset_3); + bcwc_hw_pci_post(dev_priv); + + if (var_38 == 0) + break; + + a = var_38 - 1; + if (r15 != 0) + break; + r15 = b; + } while(1); + + if (var_38 == 0) { + dev_err(&dev_priv->pdev->dev, "rd_data_dly_fifo timed out\n\n"); + ret = -EIO; + goto out; + } + + dev_info(&dev_priv->pdev->dev, "rd_data_dly_fifo succeeded\n"); + + BCWC_S2_REG_WRITE(reg_saved_1, offset_1); + bcwc_hw_pci_post(dev_priv); + + BCWC_S2_REG_WRITE(reg_saved_2, offset_2); + bcwc_hw_pci_post(dev_priv); + + BCWC_S2_REG_WRITE(reg_saved_3, offset_3); + bcwc_hw_pci_post(dev_priv); + + if (var_30 > var_2c) + var_2c = var_30; + + var_2c++; + var_30 = 7; + + if (var_2c <= 7) + var_30 = var_2c; + + if (var_30 < 7) + var_30++; + + BCWC_S2_REG_WRITE(var_30, delay_reg); + bcwc_hw_pci_post(dev_priv); + + ret = 0; +out: + return ret; } static int bcwc_hw_ddr_calibrate_re_byte_fifo(struct bcwc_private *dev_priv)