static void cris_finish (struct hw *me) { struct cris_hw *crishw; const struct hw_property *vec_for_int; const struct hw_property *multiple_int; crishw = HW_ZALLOC (me, struct cris_hw); set_hw_data (me, crishw); set_hw_ports (me, cris_ports); set_hw_port_event (me, cris_port_event); vec_for_int = hw_find_property (me, "vec-for-int"); if (vec_for_int != NULL) { unsigned32 vecsize; unsigned32 i; if (hw_property_type (vec_for_int) != array_property) hw_abort (me, "property \"vec-for-int\" has the wrong type"); vecsize = hw_property_sizeof_array (vec_for_int) / sizeof (signed_cell); if ((vecsize % 2) != 0) hw_abort (me, "translation vector does not consist of even pairs"); crishw->int_to_vec = hw_malloc (me, (vecsize/2 + 1) * sizeof (crishw->int_to_vec[0])); for (i = 0; i < vecsize/2; i++) { signed_cell portval_sc; signed_cell vec_sc; if (!hw_find_integer_array_property (me, "vec-for-int", i*2, &portval_sc) || !hw_find_integer_array_property (me, "vec-for-int", i*2 + 1, &vec_sc) || portval_sc < 0 || vec_sc < 0) hw_abort (me, "no valid vector translation pair %u", i); crishw->int_to_vec[i].portval = (unsigned32) portval_sc; crishw->int_to_vec[i].vec = (unsigned32) vec_sc; } crishw->int_to_vec[i].portval = 0; crishw->int_to_vec[i].vec = 0; } multiple_int = hw_find_property (me, "multiple-int"); if (multiple_int != NULL) { if (hw_property_type (multiple_int) == integer_property) { crishw->multiple_int_vector = hw_find_integer_property (me, "multiple-int"); crishw->multi_int_action = cris_multint_vector; } else { const char *action = hw_find_string_property (me, "multiple-int"); if (action == NULL) hw_abort (me, "property \"multiple-int\" has the wrong type"); if (strcmp (action, "abort") == 0) crishw->multi_int_action = cris_multint_abort; else if (strcmp (action, "ignore_previous") == 0) crishw->multi_int_action = cris_multint_ignore_previous; else hw_abort (me, "property \"multiple-int\" must be one of <vector number>\n" "\"abort\" and \"ignore_previous\", not \"%s\"", action); } } else crishw->multi_int_action = cris_multint_abort; }
/* Device tree options: Required: .../reg <addr> <len> .../cmdset <primary; integer> [alt; integer] Optional: .../size <device size (must be pow of 2)> .../width <8|16|32> .../write_size <integer (must be pow of 2)> .../erase_regions <number blocks> <block size> \ [<number blocks> <block size> ...] .../voltage <vcc min> <vcc max> <vpp min> <vpp max> .../timeouts <typ unit write> <typ buf write> \ <typ block erase> <typ chip erase> \ <max unit write> <max buf write> \ <max block erase> <max chip erase> .../file <file> [ro|rw] Defaults: size: <len> from "reg" width: 8 write_size: 0 (not supported) erase_region: 1 (can only erase whole chip) voltage: 0.0V (for all) timeouts: typ: 1µs, not supported, 1ms, not supported max: 1µs, 1ms, 1ms, not supported TODO: Verify user args are valid (e.g. voltage is 8 bits). */ static void attach_cfi_regs (struct hw *me, struct cfi *cfi) { address_word attach_address; int attach_space; unsigned attach_size; reg_property_spec reg; bool fd_writable; int i, ret, fd; signed_cell ival; if (hw_find_property (me, "reg") == NULL) hw_abort (me, "Missing \"reg\" property"); if (hw_find_property (me, "cmdset") == NULL) hw_abort (me, "Missing \"cmdset\" property"); if (!hw_find_reg_array_property (me, "reg", 0, ®)) hw_abort (me, "\"reg\" property must contain three addr/size entries"); hw_unit_address_to_attach_address (hw_parent (me), ®.address, &attach_space, &attach_address, me); hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); hw_attach_address (hw_parent (me), 0, attach_space, attach_address, attach_size, me); /* Extract the desired flash command set. */ ret = hw_find_integer_array_property (me, "cmdset", 0, &ival); if (ret != 1 && ret != 2) hw_abort (me, "\"cmdset\" property takes 1 or 2 entries"); cfi_encode_16bit (cfi->query.p_id, ival); for (i = 0; i < ARRAY_SIZE (cfi_cmdsets); ++i) if (cfi_cmdsets[i]->id == ival) cfi->cmdset = cfi_cmdsets[i]; if (cfi->cmdset == NULL) hw_abort (me, "cmdset %u not supported", ival); if (ret == 2) { hw_find_integer_array_property (me, "cmdset", 1, &ival); cfi_encode_16bit (cfi->query.a_id, ival); } /* Extract the desired device size. */ if (hw_find_property (me, "size")) cfi->dev_size = hw_find_integer_property (me, "size"); else cfi->dev_size = attach_size; cfi->query.dev_size = log2 (cfi->dev_size); /* Extract the desired flash width. */ if (hw_find_property (me, "width")) { cfi->width = hw_find_integer_property (me, "width"); if (cfi->width != 8 && cfi->width != 16 && cfi->width != 32) hw_abort (me, "\"width\" must be 8 or 16 or 32, not %u", cfi->width); } else /* Default to 8 bit. */ cfi->width = 8; /* Turn 8/16/32 into 1/2/4. */ cfi->width /= 8; /* Extract optional write buffer size. */ if (hw_find_property (me, "write_size")) { ival = hw_find_integer_property (me, "write_size"); cfi_encode_16bit (cfi->query.max_buf_write_len, log2 (ival)); } /* Extract optional erase regions. */ if (hw_find_property (me, "erase_regions")) { ret = hw_find_integer_array_property (me, "erase_regions", 0, &ival); if (ret % 2) hw_abort (me, "\"erase_regions\" must be specified in sets of 2"); cfi->erase_region_info = HW_NALLOC (me, unsigned char, ret / 2); cfi->erase_regions = HW_NALLOC (me, struct cfi_erase_region, ret / 2); for (i = 0; i < ret; i += 2) { unsigned blocks, size; hw_find_integer_array_property (me, "erase_regions", i, &ival); blocks = ival; hw_find_integer_array_property (me, "erase_regions", i + 1, &ival); size = ival; cfi_add_erase_region (me, cfi, blocks, size); } }