void elm_reset(void) { u32 reg_val; reg_val = elm_read_reg(ELM_SYSCONFIG); reg_val |= ELM_SYSCONFIG_SOFTRESET; elm_write_reg(ELM_SYSCONFIG, reg_val); while ((elm_read_reg(ELM_SYSSTATUS) & ELM_SYSSTATUS_RESETDONE) != ELM_SYSSTATUS_RESETDONE) ; reg_val = elm_read_reg(ELM_SYSCONFIG); reg_val &= ~ELM_SYSCONFIG_SIDLE_MASK; reg_val |= ELM_SYSCONFIG_SMART_IDLE; elm_write_reg(ELM_SYSCONFIG, reg_val); }
void elm_start_processing(void) { u32 reg_val; reg_val = elm_read_reg(ELM_SYNDROME_FRAGMENT_6); reg_val |= ELM_SYNDROME_VALID; elm_write_reg(ELM_SYNDROME_FRAGMENT_6, reg_val); }
void elm_load_syndrome(int bch_type, char *syndrome) { int reg_val; int i; for (i = 0; i < 4; i++) { reg_val = syndrome[0] | syndrome[1] << 8 | syndrome[2] << 16 | syndrome[3] << 24; elm_write_reg(ELM_SYNDROME_FRAGMENT_0 + i * 4, reg_val); syndrome += 4; } }
void elm_load_syndrome(unsigned int ecc_bytes, char *syndrome) { int reg_val; int i; for (i = 0; i < ecc_bytes; i += 4) { reg_val = syndrome[0] | syndrome[1] << 8 | syndrome[2] << 16 | syndrome[3] << 24; elm_write_reg(ELM_SYNDROME_FRAGMENT_0 + i, reg_val); syndrome += 4; } }
void elm_config(int bch_type) { u32 reg_val; u32 buffer_size = 0x7ff; reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (buffer_size << 16); elm_write_reg(ELM_LOCATION_CONFIG, reg_val); /* clearing interrupts */ reg_val = elm_read_reg(ELM_IRQSTATUS); elm_write_reg(ELM_IRQSTATUS, reg_val & INTR_STATUS_LOC_VALID_0); elm_write_reg(ELM_IRQSTATUS, INTR_STATUS_LOC_VALID_0); /* enable in interupt mode */ reg_val = elm_read_reg(ELM_IRQENABLE); reg_val |= INTR_EN_LOCATION_MASK_0; elm_write_reg(ELM_IRQENABLE, reg_val); /* config in Continuous mode */ reg_val = elm_read_reg(ELM_PAGE_CTRL); reg_val = 0; elm_write_reg(ELM_PAGE_CTRL, reg_val); }
static irqreturn_t elm_isr(int this_irq, void *dev_id) { u32 reg_val; reg_val = elm_read_reg(ELM_IRQSTATUS); if (reg_val & INTR_STATUS_LOC_VALID_0) { elm_write_reg(ELM_IRQSTATUS, reg_val & INTR_STATUS_LOC_VALID_0); complete(&elm_completion); return IRQ_HANDLED; } return IRQ_NONE; }
int elm_decode_bch_error(int bch_type, char *ecc_calc, unsigned int *err_loc) { u8 ecc_data[28] = {0}; u32 reg_val; int i, err_no; /* input calculated ECC syndrome to ELM engine */ switch (bch_type) { case ECC_TYPE_BCH16: rotate_ecc_bytes(ECC_BYTES_BCH16, ecc_calc, ecc_data); elm_load_syndrome(ECC_BYTES_BCH16, ecc_data); break; case ECC_TYPE_BCH8: rotate_ecc_bytes(ECC_BYTES_BCH8, ecc_calc, ecc_data); elm_load_syndrome(ECC_BYTES_BCH8, ecc_data); break; case ECC_TYPE_BCH4: rotate_ecc_bytes(ECC_BYTES_BCH4, ecc_calc, ecc_data); elm_load_syndrome(ECC_BYTES_BCH4, ecc_data); break; default: return -EINVAL; } /* start elm processing */ reg_val = elm_read_reg(ELM_SYNDROME_FRAGMENT_6); reg_val |= ELM_SYNDROME_VALID; elm_write_reg(ELM_SYNDROME_FRAGMENT_6, reg_val); wait_for_completion(&elm_completion); reg_val = elm_read_reg(ELM_LOCATION_STATUS); if (reg_val & ECC_CORRECTABLE_MASK) { err_no = reg_val & ECC_NB_ERRORS_MASK; for (i = 0; i < err_no; i++) { reg_val = elm_read_reg(ELM_ERROR_LOCATION_0 + i * 4); err_loc[i] = reg_val; } return err_no; } return -EINVAL; }