/* Wait for packet to be transferred into temporary buffers. */ return read_poll_timeout(readl_relaxed, tmp, !(tmp & MCHP_OTPC_SR_READ),
10000, 2000, false, otpc->base + MCHP_OTPC_SR);
}
/* * OTPC memory is organized into packets. Each packets contains a header and * a payload. Header is 4 bytes long and contains the size of the payload. * Payload size varies. The memory footprint is something as follows: * * Memory offset Memory footprint Packet ID * ------------- ---------------- --------- * * 0x0 +------------+ <-- packet 0 * | header 0 | * 0x4 +------------+ * | payload 0 | * . . * . ... . * . . * offset1 +------------+ <-- packet 1 * | header 1 | * offset1 + 0x4 +------------+ * | payload 1 | * . . * . ... . * . . * offset2 +------------+ <-- packet 2 * . . * . ... . * . . * offsetN +------------+ <-- packet N * | header N | * offsetN + 0x4 +------------+ * | payload N | * . . * . ... . * . . * +------------+ * * where offset1, offset2, offsetN depends on the size of payload 0, payload 1, * payload N-1. * * The access to memory is done on a per packet basis: the control registers * need to be updated with an offset address (within a packet range) and the * data registers will be update by controller with information contained by * that packet. E.g. if control registers are updated with any address within * the range [offset1, offset2) the data registers are updated by controller * with packet 1. Header data is accessible though MCHP_OTPC_HR register. * Payload data is accessible though MCHP_OTPC_DR and MCHP_OTPC_AR registers. * There is no direct mapping b/w the offset requested by software and the * offset returned by hardware. * * For this, the read function will return the first requested bytes in the * packet. The user will have to be aware of the memory footprint before doing * the read request.
*/ staticint mchp_otpc_read(void *priv, unsignedint off, void *val,
size_t bytes)
{ struct mchp_otpc *otpc = priv; struct mchp_otpc_packet *packet;
u32 *buf = val;
u32 offset;
size_t len = 0; int ret, payload_size;
/* * We reach this point with off being multiple of stride = 4 to * be able to cross the subsystem. Inside the driver we use continuous * unsigned integer numbers for packet id, thus divide off by 4 * before passing it to mchp_otpc_id_to_packet().
*/
packet = mchp_otpc_id_to_packet(otpc, off / 4); if (!packet) return -EINVAL;
offset = packet->offset;
while (len < bytes) {
ret = mchp_otpc_prepare_read(otpc, offset); if (ret) return ret;
/* Read and save header content. */
*buf++ = readl_relaxed(otpc->base + MCHP_OTPC_HR);
len += sizeof(*buf);
offset++; if (len >= bytes) break;
/* Read and save payload content. */
payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, *(buf - 1));
writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR); do {
*buf++ = readl_relaxed(otpc->base + MCHP_OTPC_DR);
len += sizeof(*buf);
offset++;
payload_size--;
} while (payload_size >= 0 && len < bytes);
}
return 0;
}
staticint mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size)
{ struct mchp_otpc_packet *packet;
u32 word, word_pos = 0, id = 0, npackets = 0, payload_size; int ret;
INIT_LIST_HEAD(&otpc->packets);
*size = 0;
while (*size < MCHP_OTPC_SIZE) {
ret = mchp_otpc_prepare_read(otpc, word_pos); if (ret) return ret;
word = readl_relaxed(otpc->base + MCHP_OTPC_HR);
payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, word); if (!payload_size) break;
packet = devm_kzalloc(otpc->dev, sizeof(*packet), GFP_KERNEL); if (!packet) return -ENOMEM;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.