Access to the shared registers
- configuration registers, usually being modified via “read – modify – write”.
- use mutex to protect the register access.
- use irqspin lock, if the registers are being accessed by ISR handler.
- NOTE: the if condition needs to be mutex/spinlock protected too, in the this example: if(!*IPU_CONF & (1 << 3)) *IPU_CONF |= (1 << 3);
- status registers
- “write 1 to clear” register
- if the “write” operation is atomic, no protection is needed; otherwise, protect it.
- however, if you perform a “read & write”, you need protect the entire ‘read-write” sequence.
- “read to clear” register
- protect doesn’t work in this case.
- “write 1 to clear” register
Register definition
- MAP_CONF(x) registers, each register contains one field, for map x only.
- #define MAP_CONF(x) (OFFSET + (x) * 4)
- 0 — 0
- 1– 4
- 2– 8
- #define MAP_CONF(x) (OFFSET + (x) * 4)
- MAP_CONF(x) registers, each register contains two fields: bit 0 ~ 15 for map 0/2/4; bit 16 ~ 31 for map 1/3/5.
- #define MAP_CONF(x) (OFFSET + ((x) & ~0x1) * 2) or
- #define MAP_CONF(x) (OFFSET + ((x) / 2 ) * 4)
- 0,1 — 0
- 2,3– 4
- 4,5—8
- write to the correct bit fields
- shift = (x & 1) * 16;
- *MAP_CONF(x) |= val << shift;
- MAP_CONF(x) registers, each registers contains 3 fields: bit 0 ~ 10 for map 0/3/6; bit 11 ~ 20 for map 1/4/7, bit 21~30 for map 2/5/7.
- #define MAP_CONF(x) (OFFSET + ((x)/3 * 4)
- 0,1,2— 0
- 3,4,5– 4
- 6,7,8 — 8
- write the correct bit fields
- shift = (x%3) * 10;
- *MAP_CONF(x) |= val << shift;
- #define MAP_CONF(x) (OFFSET + ((x)/3 * 4)
- An complicated example:
- MAP_CONF(x) contains 6 fields, and defined as (OFFSET + ((x) / 2 ) * 4).
- 30-26: mapping pointer for map #1 (or 3, 5, 7 when x increases) byte 2 —- 5
- 25-21: mapping pointer for map #1 (or 3, 5, 7 when x increases) byte 1. —- 4
- 16-20: mapping pointer for map #1 (or 3, 5, 7 when x increases) byte 0. —- 3
- 14-10: mapping pointer for map #0 (or 2, 4, 6 when x increases) byte 2 —- 2
- 9-5: mapping pointer for map #0 (or 2, 4, 6 when x increases) byte 1. —- 1
- 4-0: mapping pointer for map #0 (or 2, 4, 6 when x increases) byte 0 —- 0
- MAP_VAL(y) contains 4 fields, and defined as (OFFSET + ((y) / 2 ) * 4).
- 28-24: offset #1 (or 3,5,7,..).
- 23-16: mask #1
- 12-8: offset #0 (or 2,4,6…)
- 7-0: mask #0
- For a specified “map” value, e.g. 0, and 1, we want to set:
- map byte0 byte1 byte2
- —————————————————
- 0 7, 0xFF, 15, 0xFF, 23, 0xFF
- 1 5, 0xFC, 11, 0xFC, 17, 0xFC
-
- the register fields in MAP_CONF(0) will be set to the values, as marked as blue above.
- for MAP_VAL(x), it will look like this
- MAP_VAL(0) MAP_VAL(1) MAP_VAL(2)
- ————————————————————————————————
- 28-24 15 5 17
- 23-16 0xFF 0xFC 0xFC
- 12-8 7 23 11
- 7-0 0xFF 0xFF 0xFC
- the implementation of configure_map(map, offset_b0, mask_b0, offset_b1, mask_b1, offset_b2, mask_b2) would be:
- shift = (map & 1) * 16;
- pointer = map * 3;
- *MAP_CONF(map) |= ((pointer + 2) << 10 | (pointer +1 ) << 5 | (pointer) <<0 ) << shift;
- // We need use “pointer”, “pointer + 1”, “pointer + 2” to find the offset of the associated MAP_VAL(y), and the shifts.
- shift = (pointer & 1) * 16;
- *MAP_VAL(pointer) |= ((offset_b0 << 8) | (mask_b0 << 0)) << shift;
- shift = ((pointer +1) & 1) * 16;
- *MAP_VAL(pointer+1) |= ((offset_b1 << 8) | (mask_b1 << 0)) << shift;
- shift = ((pointer +2) & 1) * 16;
- *MAP_VAL(pointer+2) |= ((offset_b2 << 8) | (mask_b2 << 0)) << shift;
- MAP_CONF(x) contains 6 fields, and defined as (OFFSET + ((x) / 2 ) * 4).