Browse Source

drivers: ethernet: lan865x: Update initial setup guidelines (from AN1760)

This patch brings update of the procedure to initially configure the
LAN865x devices. It follows setup guidelines from newest AN1760 [*].

The values from "TABLE1" on the [*] must be written to the device in the
indicated order with recommended values.

This was not the case previously, as first values from in-flash allocated
(const) table were written and only afterwards calculated configuration
parameters (cfgparams) were updated.

With this patch the lan865x_conf[] table is allocated in-RAM, so
placeholder values can be updated and it can be written at once at the
end of configuration process.
Its single entry has been reduced from 8B to only 4B. Moreover, moving
it out of flash saves 512B of flash memory.

Note:
[*] - AN1760 Revision F (DS60001760G - June 2024)

Signed-off-by: Lukasz Majewski <lukma@denx.de>
pull/81485/head
Lukasz Majewski 8 months ago committed by Anas Nashif
parent
commit
3ea491cb1c
  1. 179
      drivers/ethernet/eth_lan865x.c
  2. 10
      drivers/ethernet/eth_lan865x_priv.h
  3. 5
      drivers/ethernet/oa_tc6.h

179
drivers/ethernet/eth_lan865x.c

@ -179,65 +179,109 @@ static uint8_t lan865x_read_indirect_reg(const struct device *dev, uint8_t addr, @@ -179,65 +179,109 @@ static uint8_t lan865x_read_indirect_reg(const struct device *dev, uint8_t addr,
return (uint8_t) val & mask;
}
/*
* Values in the below table for LAN865x rev. B0 and B1 (with place
* holders for cfgparamX.
*/
static oa_mem_map_t lan865x_conf[] = {
{ .mms = 0x1, .address = 0x00, .value = 0x0000 },
{ .mms = 0x4, .address = 0xD0, .value = 0x3F31 },
{ .mms = 0x4, .address = 0xE0, .value = 0xC000 },
{ .mms = 0x4, .address = 0x84, .value = 0x0000 }, /* cfgparam1 */
{ .mms = 0x4, .address = 0x8A, .value = 0x0000 }, /* cfgparam2 */
{ .mms = 0x4, .address = 0xE9, .value = 0x9E50 },
{ .mms = 0x4, .address = 0xF5, .value = 0x1CF8 },
{ .mms = 0x4, .address = 0xF4, .value = 0xC020 },
{ .mms = 0x4, .address = 0xF8, .value = 0xB900 },
{ .mms = 0x4, .address = 0xF9, .value = 0x4E53 },
{ .mms = 0x4, .address = 0x91, .value = 0x9660 },
{ .mms = 0x4, .address = 0x77, .value = 0x0028 },
{ .mms = 0x4, .address = 0x43, .value = 0x00FF },
{ .mms = 0x4, .address = 0x44, .value = 0xFFFF },
{ .mms = 0x4, .address = 0x45, .value = 0x0000 },
{ .mms = 0x4, .address = 0x53, .value = 0x00FF },
{ .mms = 0x4, .address = 0x54, .value = 0xFFFF },
{ .mms = 0x4, .address = 0x55, .value = 0x0000 },
{ .mms = 0x4, .address = 0x40, .value = 0x0002 },
{ .mms = 0x4, .address = 0x50, .value = 0x0002 },
{ .mms = 0x4, .address = 0xAD, .value = 0x0000 }, /* cfgparam3 */
{ .mms = 0x4, .address = 0xAE, .value = 0x0000 }, /* cfgparam4 */
{ .mms = 0x4, .address = 0xAF, .value = 0x0000 }, /* cfgparam5 */
{ .mms = 0x4, .address = 0xB0, .value = 0x0103 },
{ .mms = 0x4, .address = 0xB1, .value = 0x0910 },
{ .mms = 0x4, .address = 0xB2, .value = 0x1D26 },
{ .mms = 0x4, .address = 0xB3, .value = 0x002A },
{ .mms = 0x4, .address = 0xB4, .value = 0x0103 },
{ .mms = 0x4, .address = 0xB5, .value = 0x070D },
{ .mms = 0x4, .address = 0xB6, .value = 0x1720 },
{ .mms = 0x4, .address = 0xB7, .value = 0x0027 },
{ .mms = 0x4, .address = 0xB8, .value = 0x0509 },
{ .mms = 0x4, .address = 0xB9, .value = 0x0E13 },
{ .mms = 0x4, .address = 0xBA, .value = 0x1C25 },
{ .mms = 0x4, .address = 0xBB, .value = 0x002B },
{ .mms = 0x4, .address = 0x0C, .value = 0x0100 },
{ .mms = 0x4, .address = 0x81, .value = 0x00E0 },
};
/* Based on AN1760 DS60001760G pseudo code */
static int lan865x_init_chip(const struct device *dev, uint8_t silicon_rev)
{
uint16_t cfgparam1, cfgparam2, cfgparam3, cfgparam4, cfgparam5;
uint8_t i, size = ARRAY_SIZE(lan865x_conf);
struct lan865x_data *ctx = dev->data;
int8_t offset1 = 0, offset2 = 0;
uint8_t value1, value2;
int8_t offset1 = 0, offset2 = 0, ret;
uint16_t value3, value4, value5, value6, value7;
uint16_t cfgparam1, cfgparam2, cfgparam3, cfgparam4, cfgparam5;
uint32_t val;
ret = lan865x_read_indirect_reg(dev, 0x05, 0x40);
if (ret == 0) {
LOG_ERR("LAN865x error! Please contact microchip support for replacement.");
return -EIO;
}
/* Enable protected control RW */
oa_tc6_set_protected_ctrl(ctx->tc6, true);
value1 = lan865x_read_indirect_reg(dev, 0x04, 0x1F);
if ((value1 & 0x10) != 0) { /* Convert uint8_t to int8_t */
offset1 = value1 | 0xE0;
if (offset1 < -5) {
LOG_ERR("LAN865x internal error!");
return -EIO;
}
offset1 = (int8_t)((uint8_t)value1 - 0x20);
} else {
offset1 = value1;
offset1 = (int8_t)value1;
}
value2 = lan865x_read_indirect_reg(dev, 0x08, 0x1F);
if ((value2 & 0x10) != 0) { /* Convert uint8_t to int8_t */
offset2 = value2 | 0xE0;
offset2 = (int8_t)((uint8_t)value2 - 0x20);
} else {
offset2 = value2;
}
oa_tc6_reg_read(ctx->tc6, 0x00040084, &val);
value3 = (uint16_t)val;
oa_tc6_reg_read(ctx->tc6, 0x0004008A, &val);
value4 = (uint16_t)val;
oa_tc6_reg_read(ctx->tc6, 0x000400AD, &val);
value5 = (uint16_t)val;
oa_tc6_reg_read(ctx->tc6, 0x000400AE, &val);
value6 = (uint8_t)val;
oa_tc6_reg_read(ctx->tc6, 0x000400AF, &val);
value7 = (uint8_t)val;
offset2 = (int8_t)value2;
}
cfgparam1 = (uint16_t) (((9 + offset1) & 0x3F) << 10) |
(uint16_t) (((14 + offset1) & 0x3F) << 4) | 0x03;
cfgparam2 = (uint16_t) (((40 + offset2) & 0x3F) << 10);
cfgparam3 = (uint16_t) (((5 + offset1) & 0x3F) << 8) |
(uint16_t) ((9 + offset1) & 0x3F);
cfgparam4 = (uint16_t) (((9 + offset1) & 0x3F) << 8) |
(uint16_t) ((14 + offset1) & 0x3F);
cfgparam5 = (uint16_t) (((17 + offset1) & 0x3F) << 8) |
(uint16_t) ((22 + offset1) & 0x3F);
lan865x_update_dev_cfg_array(lan865x_conf, size,
MMS_REG(0x4, 0x84), cfgparam1);
lan865x_update_dev_cfg_array(lan865x_conf, size,
MMS_REG(0x4, 0x8A), cfgparam2);
lan865x_update_dev_cfg_array(lan865x_conf, size,
MMS_REG(0x4, 0xAD), cfgparam3);
lan865x_update_dev_cfg_array(lan865x_conf, size,
MMS_REG(0x4, 0xAE), cfgparam4);
lan865x_update_dev_cfg_array(lan865x_conf, size,
MMS_REG(0x4, 0xAF), cfgparam5);
cfgparam1 = (value3 & 0xF) | (((9 + offset1) << 10) | ((14 + offset1) << 4));
cfgparam2 = (value4 & 0x3FF) | ((40 + offset2) << 10);
cfgparam3 = (value5 & 0xC0C0) | (((5 + offset1) << 8) | (9 + offset1));
cfgparam4 = (value6 & 0xC0C0) | (((9 + offset1) << 8) | (14 + offset1));
cfgparam5 = (value7 & 0xC0C0) | (((17 + offset1) << 8) | (22 + offset1));
if (silicon_rev == 1) {
/* For silicon rev 1 (B0): (bit [3..0] from 0x0A0084 */
lan865x_update_dev_cfg_array(lan865x_conf, size,
MMS_REG(0x4, 0xD0), 0x5F21);
}
oa_tc6_reg_write(ctx->tc6, 0x00040084, (uint32_t) cfgparam1);
oa_tc6_reg_write(ctx->tc6, 0x0004008A, (uint32_t) cfgparam2);
oa_tc6_reg_write(ctx->tc6, 0x000400AD, (uint32_t) cfgparam3);
oa_tc6_reg_write(ctx->tc6, 0x000400AE, (uint32_t) cfgparam4);
oa_tc6_reg_write(ctx->tc6, 0x000400AF, (uint32_t) cfgparam5);
/* Write LAN865x config with correct order */
for (i = 0; i < size; i++) {
oa_tc6_reg_write(ctx->tc6, MMS_REG(lan865x_conf[i].mms,
lan865x_conf[i].address),
(uint32_t)lan865x_conf[i].value);
}
return 0;
}
@ -312,58 +356,9 @@ static int lan865x_set_specific_multicast_addr(const struct device *dev) @@ -312,58 +356,9 @@ static int lan865x_set_specific_multicast_addr(const struct device *dev)
static int lan865x_default_config(const struct device *dev, uint8_t silicon_rev)
{
/* Values in the below table are the same for LAN865x rev. B0 and B1 */
static const oa_mem_map_t lan865x_conf[] = {
{ .address = 0x00010000, .value = 0x00000000 },
{ .address = 0x00040091, .value = 0x00009660 },
{ .address = 0x00040081, .value = 0x00000080 },
{ .address = 0x00010077, .value = 0x00000028 },
{ .address = 0x00040043, .value = 0x000000FF },
{ .address = 0x00040044, .value = 0x0000FFFF },
{ .address = 0x00040045, .value = 0x00000000 },
{ .address = 0x00040053, .value = 0x000000FF },
{ .address = 0x00040054, .value = 0x0000FFFF },
{ .address = 0x00040055, .value = 0x00000000 },
{ .address = 0x00040040, .value = 0x00000002 },
{ .address = 0x00040050, .value = 0x00000002 },
{ .address = 0x000400E9, .value = 0x00009E50 },
{ .address = 0x000400F5, .value = 0x00001CF8 },
{ .address = 0x000400F4, .value = 0x0000C020 },
{ .address = 0x000400F8, .value = 0x00009B00 },
{ .address = 0x000400F9, .value = 0x00004E53 },
{ .address = 0x000400B0, .value = 0x00000103 },
{ .address = 0x000400B1, .value = 0x00000910 },
{ .address = 0x000400B2, .value = 0x00001D26 },
{ .address = 0x000400B3, .value = 0x0000002A },
{ .address = 0x000400B4, .value = 0x00000103 },
{ .address = 0x000400B5, .value = 0x0000070D },
{ .address = 0x000400B6, .value = 0x00001720 },
{ .address = 0x000400B7, .value = 0x00000027 },
{ .address = 0x000400B8, .value = 0x00000509 },
{ .address = 0x000400B9, .value = 0x00000E13 },
{ .address = 0x000400BA, .value = 0x00001C25 },
{ .address = 0x000400BB, .value = 0x0000002B },
{ .address = 0x0000000C, .value = 0x00000100 },
{ .address = 0x00040081, .value = 0x000000E0 },
};
const struct lan865x_config *cfg = dev->config;
uint8_t i, size = ARRAY_SIZE(lan865x_conf);
struct lan865x_data *ctx = dev->data;
int ret;
/* Enable protected control RW */
oa_tc6_set_protected_ctrl(ctx->tc6, true);
for (i = 0; i < size; i++) {
oa_tc6_reg_write(ctx->tc6, lan865x_conf[i].address,
lan865x_conf[i].value);
}
if (silicon_rev == 1) {
/* For silicon rev 1 (B0): (bit [3..0] from 0x0A0084 */
oa_tc6_reg_write(ctx->tc6, 0x000400D0, 0x5F21);
}
lan865x_write_macaddress(dev);
lan865x_set_specific_multicast_addr(dev);

10
drivers/ethernet/eth_lan865x_priv.h

@ -81,4 +81,14 @@ struct lan865x_data { @@ -81,4 +81,14 @@ struct lan865x_data {
k_tid_t tid_int;
};
static inline void lan865x_update_dev_cfg_array(oa_mem_map_t *cfg, uint8_t size,
uint32_t addr, uint16_t val)
{
for (uint8_t i = 0; i < size; i++) {
if (cfg[i].address == addr) {
cfg[i].value = val;
}
}
}
#endif /* ETH_LAN865X_PRIV_H__ */

5
drivers/ethernet/oa_tc6.h

@ -113,8 +113,9 @@ struct oa_tc6 { @@ -113,8 +113,9 @@ struct oa_tc6 {
};
typedef struct {
uint32_t address;
uint32_t value;
uint8_t mms;
uint8_t address;
uint16_t value;
} oa_mem_map_t;
/**

Loading…
Cancel
Save