blob: 9f4d46e2383df6f351bfd3d9375344ce08c0337c [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
* Copyright 2020, HENSOLDT Cyber GmbH
*
* SPDX-License-Identifier: GPL-2.0-only
*/
/* Author Alex Kroh */
#include "ocotp_ctrl.h"
#include <assert.h>
#include <stdio.h>
#include <utils/util.h>
#include "unimplemented.h"
/*
* NOTE: ocotp clock is sources by ipg_clk but must be gated
* CCM_CGR2[CG6]
*/
#if defined(CONFIG_PLAT_IMX6)
#define IMX6_OCOTP_PADDR 0x021BC000
#define IMX6_OCOTP_SIZE 0x00004000
#elif defined(CONFIG_PLAT_IMX8MQ_EVK)
#define IMX6_OCOTP_PADDR 0x30350000
#define IMX6_OCOTP_SIZE 0x00010000
#endif
#define TIMING_WAIT(x) ((x) << 22)
#define TIMING_SREAD(x) ((x) << 16)
#define TIMING_RELAX(x) ((x) << 12)
#define TIMING_SPROG(x) ((x) << 0)
#define TIMING_WAIT_MAX 0x03f
#define TIMING_SREAD_MAX 0x03f
#define TIMING_RELAX_MAX 0x00f
#define TIMING_SPROG_MAX 0xfff
#define CTRL_UNLOCK_KEY (0x3E77 << 16)
#define CTRL_RELOAD_SHADOWS BIT(10)
#define CTRL_ERROR BIT(9)
#define CTRL_BUSY BIT(8)
#define CTRL_ADDR(x) ((x) << 0)
#define LOCK_FUSE BIT(0)
#define LOCK_SHADOW BIT(1)
#define LOCK_ANALOG(x) ((x) << 18)
#define LOCK_GP2(x) ((x) << 12)
#define LOCK_CP1(x) ((x) << 10)
#define LOCK_MAC(x) ((x) << 8)
#define LOCK_MEMTRIM(x) ((x) << 4)
#define LOCK_BOOTCFG(x) ((x) << 2)
#define LOCK_TESTER(x) ((x) << 0)
#define FADDR_LOCK 0x00
#define FADDR_MAC0 0x22
#define FADDR_MAC1 0x23
struct ocotp_regs {
uint32_t ctrl; /* 000 */
uint32_t ctrl_set; /* 004 */
uint32_t ctrl_clr; /* 008 */
uint32_t ctrl_tog; /* 00C */
uint32_t timing; /* 010 */
uint32_t res1[3]; /* 014 */
uint32_t data; /* 020 */
uint32_t res2[3]; /* 024 */
uint32_t read_ctrl; /* 030 */
uint32_t res3[3]; /* 034 */
uint32_t read_fuse_data; /* 040 */
uint32_t res4[3]; /* 044 */
uint32_t sw_sticky; /* 050 */
uint32_t res5[3]; /* 054 */
uint32_t scs; /* 060 */
uint32_t scs_set; /* 064 */
uint32_t scs_clr; /* 068 */
uint32_t scs_tog; /* 06C */
uint32_t res6[8]; /* 070 */
uint32_t ver; /* 090 */
uint32_t res7[219]; /* 094 */
/* Bank 0 */
uint32_t lock; /* 400 */
uint32_t res8[3];
uint32_t cfg0; /* 410 */
uint32_t res9[3];
uint32_t cfg1; /* 420 */
uint32_t res10[3];
uint32_t cfg2; /* 430 */
uint32_t res11[3];
uint32_t cfg3; /* 440 */
uint32_t res12[3];
uint32_t cfg4; /* 450 */
uint32_t res13[3];
uint32_t cfg5; /* 460 */
uint32_t res14[3];
uint32_t cfg6; /* 470 */
uint32_t res15[3];
/* Bank 1 */
uint32_t mem0; /* 480 */
uint32_t res16[3];
uint32_t mem1; /* 490 */
uint32_t res17[3];
uint32_t mem2; /* 4A0 */
uint32_t res18[3];
uint32_t mem3; /* 4B0 */
uint32_t res19[3];
uint32_t mem4; /* 4C0 */
uint32_t res20[3];
uint32_t ana0; /* 4D0 */
uint32_t res21[3];
uint32_t ana1; /* 4E0 */
uint32_t res22[3];
uint32_t ana2; /* 4F0 */
uint32_t res23[3];
uint32_t res24[32]; /* 500 */
/* Bank 3 shadow */
uint32_t srk0; /* 580 */
uint32_t res25[3];
uint32_t srk1; /* 590 */
uint32_t res26[3];
uint32_t srk2; /* 5A0 */
uint32_t res27[3];
uint32_t srk3; /* 5B0 */
uint32_t res28[3];
uint32_t srk4; /* 5C0 */
uint32_t res29[3];
uint32_t srk5; /* 5D0 */
uint32_t res30[3];
uint32_t srk6; /* 5E0 */
uint32_t res31[3];
uint32_t srk7; /* 5F0 */
uint32_t res32[3];
/* Bank 4 */
uint32_t resp0; /* 600 */
uint32_t res33[3];
uint32_t hsjc_resp1; /* 610 */
uint32_t res34[3];
uint32_t mac0; /* 620 */
uint32_t res35[3];
uint32_t mac1; /* 630 */
uint32_t res36[3];
#ifdef CONFIG_PLAT_IMX6SX
uint32_t mac2; /* 640 */
uint32_t res37[7];
#else
uint32_t res37[8];
#endif
uint32_t gp0; /* 660 */
uint32_t res38[3];
uint32_t gp1; /* 670 */
uint32_t res39[3];
uint32_t res40[20];
/* Bank 5 */
uint32_t misc_conf; /* 6D0 */
uint32_t res41[3];
uint32_t field_return; /* 6E0 */
uint32_t res42[3];
uint32_t srk_revoke; /* 6F0 */
uint32_t res43[3];
};
struct ocotp {
int dummy;
};
typedef volatile struct ocotp_regs ocotp_regs_t;
static inline ocotp_regs_t *ocotp_get_regs(struct ocotp *ocotp)
{
return (ocotp_regs_t *)ocotp;
}
struct ocotp *ocotp_init(ps_io_mapper_t *io_mapper)
{
return (struct ocotp *)RESOURCE(io_mapper, IMX6_OCOTP);
}
void ocotp_free(struct ocotp *ocotp, ps_io_mapper_t *io_mapper)
{
UNRESOURCE(io_mapper, IMX6_OCOTP, ocotp);
}
uint64_t ocotp_get_mac(struct ocotp *ocotp, unsigned int id)
{
assert(ocotp);
ocotp_regs_t *regs = ocotp_get_regs(ocotp);
/* i.MX6 dual/quad has one ENET device, i.MX6 Solo X has two. OCOTP usage
* is defined in the TRM as:
* 0x620 - 0x630[15:0]: MAC1_ADDR
* 0x630[31:16] - 0x640: MAC2_ADDR
* Which means if OCOTP was raw memory the MACs
* ENET1: <aa>:<bb>:<cc>:<dd>:<ee>:<ff>
* ENET2: <gg>:<hh>:<ii>:<jj>:<kk>:<ll>
* are stored as
* 0x620: <ff> <ee> <dd> <cc> xx xx xx xx xx xx xx xx xx xx xx xx
* 0x630: <bb> <aa> <ll> <kk> xx xx xx xx xx xx xx xx xx xx xx xx
* 0x640: <jj> <ii> <hh> <gg> xx xx xx xx xx xx xx xx xx xx xx xx
* Reading the OCOTP contents as little endian uint32_t gives
* mac0 = 0x<cc><dd><ee><ff>
* mac1 = 0x<kk><ll><aa><bb>
* mac2 = 0x<gg><hh><ii><jj>
* We return the MAC as uint64_t
* ENET1: 0x0000<aa><bb><cc><dd><ee><ff>
* ENET2: 0x0000<gg><hh><ii><jj><kk><ll>
*/
uint64_t mac = 0;
switch (id) {
case 0:
/* 0x0000<aa><bb><cc><dd><ee><ff> */
mac = ((uint64_t)((uint16_t)regs->mac1) << 32) | regs->mac0;
break;
#ifdef CONFIG_PLAT_IMX6SX
case 1:
/* 0x0000<gg><hh><ii><jj><kk><ll> */
mac = ((uint64_t)regs->mac2 << 16) | (regs->mac1 >> 16);
break;
#endif
default:
ZF_LOGE("Unsupported MAC ID %u", id);
return 0;
} /* switch (id) */
/* at least one bit must be set in the MAC to consider it valid */
if (0 == mac) {
ZF_LOGE("no MAC in OCOTP for id %d", id);
return 0;
}
ZF_LOGI("OCOTP MAC #%u: %02x:%02x:%02x:%02x:%02x:%02x",
id, (uint8_t)(mac >> 40), (uint8_t)(mac >> 32),
(uint8_t)(mac >> 24), (uint8_t)(mac >> 16), (uint8_t)(mac >> 8),
(uint8_t)mac);
return mac;
}