diff options
author | Tom Rini <trini@konsulko.com> | 2015-04-24 13:43:24 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2015-04-24 13:43:24 -0400 |
commit | 3f6dcdb9cd4dbda226a1474f1e9398413e906b41 (patch) | |
tree | fb3a7d7873e9c14a3733197e4cc028ce90827970 /drivers | |
parent | d8c1d5d5fb6eafbc532982125f006e49f2c40e71 (diff) | |
parent | ab10d73d2fc13bd5baf5024e54ad92641d238bdb (diff) | |
download | u-boot-imx-3f6dcdb9cd4dbda226a1474f1e9398413e906b41.zip u-boot-imx-3f6dcdb9cd4dbda226a1474f1e9398413e906b41.tar.gz u-boot-imx-3f6dcdb9cd4dbda226a1474f1e9398413e906b41.tar.bz2 |
Merge branch 'master' of git://git.denx.de/u-boot-fsl-qoriq
Diffstat (limited to 'drivers')
45 files changed, 4785 insertions, 329 deletions
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index 3919257..8367c95 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -313,7 +313,10 @@ static void set_timing_cfg_0(const unsigned int ctrl_num, #ifdef CONFIG_SYS_FSL_DDR4 /* tXP=max(4nCK, 6ns) */ int txp = max((int)mclk_ps * 4, 6000); /* unit=ps */ - trwt_mclk = 2; + unsigned int data_rate = get_ddr_freq(ctrl_num); + + /* for faster clock, need more time for data setup */ + trwt_mclk = (data_rate/1000000 > 1900) ? 3 : 2; twrt_mclk = 1; act_pd_exit_mclk = picos_to_mclk(ctrl_num, txp); pre_pd_exit_mclk = act_pd_exit_mclk; @@ -338,7 +341,7 @@ static void set_timing_cfg_0(const unsigned int ctrl_num, */ txp = max((int)mclk_ps * 3, (mclk_ps > 1540 ? 7500 : 6000)); - ip_rev = fsl_ddr_get_version(); + ip_rev = fsl_ddr_get_version(ctrl_num); if (ip_rev >= 0x40700) { /* * MRS_CYC = max(tMRD, tMOD) @@ -544,7 +547,7 @@ static void set_timing_cfg_1(const unsigned int ctrl_num, * we need set extend bit for it at * TIMING_CFG_3[EXT_CASLAT] */ - if (fsl_ddr_get_version() <= 0x40400) + if (fsl_ddr_get_version(ctrl_num) <= 0x40400) caslat_ctrl = 2 * cas_latency - 1; else caslat_ctrl = (cas_latency - 1) << 1; @@ -1113,16 +1116,32 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr, int i; unsigned short esdmode4 = 0; /* Extended SDRAM mode 4 */ unsigned short esdmode5; /* Extended SDRAM mode 5 */ + int rtt_park = 0; - esdmode5 = 0x00000400; /* Data mask enabled */ + if (ddr->cs[0].config & SDRAM_CS_CONFIG_EN) { + esdmode5 = 0x00000500; /* Data mask enable, RTT_PARK CS0 */ + rtt_park = 1; + } else { + esdmode5 = 0x00000400; /* Data mask enabled */ + } ddr->ddr_sdram_mode_9 = (0 | ((esdmode4 & 0xffff) << 16) | ((esdmode5 & 0xffff) << 0) ); + + /* only mode_9 use 0x500, others use 0x400 */ + debug("FSLDDR: ddr_sdram_mode_9) = 0x%08x\n", ddr->ddr_sdram_mode_9); if (unq_mrs_en) { /* unique mode registers are supported */ for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (!rtt_park && + (ddr->cs[i].config & SDRAM_CS_CONFIG_EN)) { + esdmode5 |= 0x00000500; /* RTT_PARK */ + rtt_park = 1; + } else { + esdmode5 = 0x00000400; + } switch (i) { case 1: ddr->ddr_sdram_mode_11 = (0 @@ -1970,31 +1989,41 @@ static void set_ddr_dq_mapping(fsl_ddr_cfg_regs_t *ddr, const dimm_params_t *dimm_params) { unsigned int acc_ecc_en = (ddr->ddr_sdram_cfg >> 2) & 0x1; + int i; + + for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { + if (dimm_params[i].n_ranks) + break; + } + if (i >= CONFIG_DIMM_SLOTS_PER_CTLR) { + puts("DDR error: no DIMM found!\n"); + return; + } - ddr->dq_map_0 = ((dimm_params->dq_mapping[0] & 0x3F) << 26) | - ((dimm_params->dq_mapping[1] & 0x3F) << 20) | - ((dimm_params->dq_mapping[2] & 0x3F) << 14) | - ((dimm_params->dq_mapping[3] & 0x3F) << 8) | - ((dimm_params->dq_mapping[4] & 0x3F) << 2); + ddr->dq_map_0 = ((dimm_params[i].dq_mapping[0] & 0x3F) << 26) | + ((dimm_params[i].dq_mapping[1] & 0x3F) << 20) | + ((dimm_params[i].dq_mapping[2] & 0x3F) << 14) | + ((dimm_params[i].dq_mapping[3] & 0x3F) << 8) | + ((dimm_params[i].dq_mapping[4] & 0x3F) << 2); - ddr->dq_map_1 = ((dimm_params->dq_mapping[5] & 0x3F) << 26) | - ((dimm_params->dq_mapping[6] & 0x3F) << 20) | - ((dimm_params->dq_mapping[7] & 0x3F) << 14) | - ((dimm_params->dq_mapping[10] & 0x3F) << 8) | - ((dimm_params->dq_mapping[11] & 0x3F) << 2); + ddr->dq_map_1 = ((dimm_params[i].dq_mapping[5] & 0x3F) << 26) | + ((dimm_params[i].dq_mapping[6] & 0x3F) << 20) | + ((dimm_params[i].dq_mapping[7] & 0x3F) << 14) | + ((dimm_params[i].dq_mapping[10] & 0x3F) << 8) | + ((dimm_params[i].dq_mapping[11] & 0x3F) << 2); - ddr->dq_map_2 = ((dimm_params->dq_mapping[12] & 0x3F) << 26) | - ((dimm_params->dq_mapping[13] & 0x3F) << 20) | - ((dimm_params->dq_mapping[14] & 0x3F) << 14) | - ((dimm_params->dq_mapping[15] & 0x3F) << 8) | - ((dimm_params->dq_mapping[16] & 0x3F) << 2); + ddr->dq_map_2 = ((dimm_params[i].dq_mapping[12] & 0x3F) << 26) | + ((dimm_params[i].dq_mapping[13] & 0x3F) << 20) | + ((dimm_params[i].dq_mapping[14] & 0x3F) << 14) | + ((dimm_params[i].dq_mapping[15] & 0x3F) << 8) | + ((dimm_params[i].dq_mapping[16] & 0x3F) << 2); /* dq_map for ECC[4:7] is set to 0 if accumulated ECC is enabled */ - ddr->dq_map_3 = ((dimm_params->dq_mapping[17] & 0x3F) << 26) | - ((dimm_params->dq_mapping[8] & 0x3F) << 20) | + ddr->dq_map_3 = ((dimm_params[i].dq_mapping[17] & 0x3F) << 26) | + ((dimm_params[i].dq_mapping[8] & 0x3F) << 20) | (acc_ecc_en ? 0 : - (dimm_params->dq_mapping[9] & 0x3F) << 14) | - dimm_params->dq_mapping_ors; + (dimm_params[i].dq_mapping[9] & 0x3F) << 14) | + dimm_params[i].dq_mapping_ors; debug("FSLDDR: dq_map_0 = 0x%08x\n", ddr->dq_map_0); debug("FSLDDR: dq_map_1 = 0x%08x\n", ddr->dq_map_1); @@ -2357,7 +2386,7 @@ compute_fsl_memctl_config_regs(const unsigned int ctrl_num, set_ddr_cdr1(ddr, popts); set_ddr_cdr2(ddr, popts); set_ddr_sdram_cfg(ddr, popts, common_dimm); - ip_rev = fsl_ddr_get_version(); + ip_rev = fsl_ddr_get_version(ctrl_num); if (ip_rev > 0x40400) unq_mrs_en = 1; diff --git a/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c index bbfb4ee..42834ca 100644 --- a/drivers/ddr/fsl/ddr4_dimm_params.c +++ b/drivers/ddr/fsl/ddr4_dimm_params.c @@ -135,7 +135,8 @@ unsigned int ddr_compute_dimm_parameters(const unsigned int ctrl_num, if (spd->mem_type) { if (spd->mem_type != SPD_MEMTYPE_DDR4) { - printf("DIMM %u: is not a DDR4 SPD.\n", dimm_number); + printf("Ctrl %u DIMM %u: is not a DDR4 SPD.\n", + ctrl_num, dimm_number); return 1; } } else { diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c index d9fce7d..49e4688 100644 --- a/drivers/ddr/fsl/fsl_ddr_gen4.c +++ b/drivers/ddr/fsl/fsl_ddr_gen4.c @@ -1,5 +1,5 @@ /* - * Copyright 2014 Freescale Semiconductor, Inc. + * Copyright 2014-2015 Freescale Semiconductor, Inc. * * SPDX-License-Identifier: GPL-2.0+ */ @@ -11,6 +11,22 @@ #include <fsl_immap.h> #include <fsl_ddr.h> +#ifdef CONFIG_SYS_FSL_ERRATUM_A008511 +static void set_wait_for_bits_clear(void *ptr, u32 value, u32 bits) +{ + int timeout = 1000; + + ddr_out32(ptr, value); + + while (ddr_in32(ptr) & bits) { + udelay(100); + timeout--; + } + if (timeout <= 0) + puts("Error: A007865 wait for clear timeout.\n"); +} +#endif /* CONFIG_SYS_FSL_ERRATUM_A008511 */ + #if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) #error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL #endif @@ -36,6 +52,16 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, defined(CONFIG_SYS_FSL_ERRATUM_A008514) u32 *eddrtqcr1; #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A008511 + u32 temp32, mr6; +#endif +#ifdef CONFIG_FSL_DDR_BIST + u32 mtcr, err_detect, err_sbe; + u32 cs0_bnds, cs1_bnds, cs2_bnds, cs3_bnds, cs0_config; +#endif +#ifdef CONFIG_FSL_DDR_BIST + char buffer[CONFIG_SYS_CBSIZE]; +#endif switch (ctrl_num) { case 0: @@ -214,6 +240,21 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, ddr_setbits32(ddr->debug[28], 0x9 << 20); #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A008511 + /* Part 1 of 2 */ + /* This erraum only applies to verion 5.2.0 */ + if (fsl_ddr_get_version(ctrl_num) == 0x50200) { + /* Disable DRAM VRef training */ + ddr_out32(&ddr->ddr_cdr2, + regs->ddr_cdr2 & ~DDR_CDR2_VREF_TRAIN_EN); + /* Disable deskew */ + ddr_out32(&ddr->debug[28], 0x400); + /* Disable D_INIT */ + ddr_out32(&ddr->sdram_cfg_2, + regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT); + ddr_out32(&ddr->debug[25], 0x9000); + } +#endif /* * For RDIMMs, JEDEC spec requires clocks to be stable before reset is * deasserted. Clocks start when any chip select is enabled and clock @@ -261,6 +302,66 @@ step2: mb(); isb(); +#ifdef CONFIG_SYS_FSL_ERRATUM_A008511 + /* Part 2 of 2 */ + /* This erraum only applies to verion 5.2.0 */ + if (fsl_ddr_get_version(ctrl_num) == 0x50200) { + /* Wait for idle */ + timeout = 200; + while (!(ddr_in32(&ddr->debug[1]) & 0x2) && + (timeout > 0)) { + udelay(100); + timeout--; + } + if (timeout <= 0) { + printf("Controler %d timeout, debug_2 = %x\n", + ctrl_num, ddr_in32(&ddr->debug[1])); + } + /* Set VREF */ + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (!(regs->cs[i].config & SDRAM_CS_CONFIG_EN)) + continue; + + mr6 = (regs->ddr_sdram_mode_10 >> 16) | + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL(i) | + MD_CNTL_MD_SEL(6) | + 0x00200000; + temp32 = mr6 | 0xc0; + set_wait_for_bits_clear(&ddr->sdram_md_cntl, + temp32, MD_CNTL_MD_EN); + udelay(1); + debug("MR6 = 0x%08x\n", temp32); + temp32 = mr6 | 0xf0; + set_wait_for_bits_clear(&ddr->sdram_md_cntl, + temp32, MD_CNTL_MD_EN); + udelay(1); + debug("MR6 = 0x%08x\n", temp32); + temp32 = mr6 | 0x70; + set_wait_for_bits_clear(&ddr->sdram_md_cntl, + temp32, MD_CNTL_MD_EN); + udelay(1); + debug("MR6 = 0x%08x\n", temp32); + } + ddr_out32(&ddr->sdram_md_cntl, 0); + ddr_out32(&ddr->debug[28], 0); /* Enable deskew */ + ddr_out32(&ddr->debug[1], 0x400); /* restart deskew */ + /* wait for idle */ + timeout = 200; + while (!(ddr_in32(&ddr->debug[1]) & 0x2) && + (timeout > 0)) { + udelay(100); + timeout--; + } + if (timeout <= 0) { + printf("Controler %d timeout, debug_2 = %x\n", + ctrl_num, ddr_in32(&ddr->debug[1])); + } + /* Restore D_INIT */ + ddr_out32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); + } +#endif /* CONFIG_SYS_FSL_ERRATUM_A008511 */ + total_gb_size_per_controller = 0; for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { if (!(regs->cs[i].config & 0x80000000)) @@ -309,4 +410,70 @@ step2: ddr_out32(&ddr->sdram_cfg_2, temp_sdram_cfg); } #endif + +#ifdef CONFIG_FSL_DDR_BIST +#define BIST_PATTERN1 0xFFFFFFFF +#define BIST_PATTERN2 0x0 +#define BIST_CR 0x80010000 +#define BIST_CR_EN 0x80000000 +#define BIST_CR_STAT 0x00000001 +#define CTLR_INTLV_MASK 0x20000000 + /* Perform build-in test on memory. Three-way interleaving is not yet + * supported by this code. */ + if (getenv_f("ddr_bist", buffer, CONFIG_SYS_CBSIZE) >= 0) { + puts("Running BIST test. This will take a while..."); + cs0_config = ddr_in32(&ddr->cs0_config); + if (cs0_config & CTLR_INTLV_MASK) { + cs0_bnds = ddr_in32(&cs0_bnds); + cs1_bnds = ddr_in32(&cs1_bnds); + cs2_bnds = ddr_in32(&cs2_bnds); + cs3_bnds = ddr_in32(&cs3_bnds); + /* set bnds to non-interleaving */ + ddr_out32(&cs0_bnds, (cs0_bnds & 0xfffefffe) >> 1); + ddr_out32(&cs1_bnds, (cs1_bnds & 0xfffefffe) >> 1); + ddr_out32(&cs2_bnds, (cs2_bnds & 0xfffefffe) >> 1); + ddr_out32(&cs3_bnds, (cs3_bnds & 0xfffefffe) >> 1); + } + ddr_out32(&ddr->mtp1, BIST_PATTERN1); + ddr_out32(&ddr->mtp2, BIST_PATTERN1); + ddr_out32(&ddr->mtp3, BIST_PATTERN2); + ddr_out32(&ddr->mtp4, BIST_PATTERN2); + ddr_out32(&ddr->mtp5, BIST_PATTERN1); + ddr_out32(&ddr->mtp6, BIST_PATTERN1); + ddr_out32(&ddr->mtp7, BIST_PATTERN2); + ddr_out32(&ddr->mtp8, BIST_PATTERN2); + ddr_out32(&ddr->mtp9, BIST_PATTERN1); + ddr_out32(&ddr->mtp10, BIST_PATTERN2); + mtcr = BIST_CR; + ddr_out32(&ddr->mtcr, mtcr); + timeout = 100; + while (timeout > 0 && (mtcr & BIST_CR_EN)) { + mdelay(1000); + timeout--; + mtcr = ddr_in32(&ddr->mtcr); + } + if (timeout <= 0) + puts("Timeout\n"); + else + puts("Done\n"); + err_detect = ddr_in32(&ddr->err_detect); + err_sbe = ddr_in32(&ddr->err_sbe); + if (mtcr & BIST_CR_STAT) { + printf("BIST test failed on controller %d.\n", + ctrl_num); + } + if (err_detect || (err_sbe & 0xffff)) { + printf("ECC error detected on controller %d.\n", + ctrl_num); + } + + if (cs0_config & CTLR_INTLV_MASK) { + /* restore bnds registers */ + ddr_out32(&cs0_bnds, cs0_bnds); + ddr_out32(&cs1_bnds, cs1_bnds); + ddr_out32(&cs2_bnds, cs2_bnds); + ddr_out32(&cs3_bnds, cs3_bnds); + } + } +#endif } diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c index 32ba6d8..d23e6e5 100644 --- a/drivers/ddr/fsl/interactive.c +++ b/drivers/ddr/fsl/interactive.c @@ -205,6 +205,8 @@ static void lowest_common_dimm_parameters_edit(fsl_ddr_info_t *pinfo, #define DIMM_PARM(x) {#x, offsetof(dimm_params_t, x), \ sizeof((dimm_params_t *)0)->x, 0} +#define DIMM_PARM_HEX(x) {#x, offsetof(dimm_params_t, x), \ + sizeof((dimm_params_t *)0)->x, 1} static void fsl_ddr_dimm_parameters_edit(fsl_ddr_info_t *pinfo, unsigned int ctrl_num, @@ -220,6 +222,7 @@ static void fsl_ddr_dimm_parameters_edit(fsl_ddr_info_t *pinfo, DIMM_PARM(primary_sdram_width), DIMM_PARM(ec_sdram_width), DIMM_PARM(registered_dimm), + DIMM_PARM(mirrored_dimm), DIMM_PARM(device_width), DIMM_PARM(n_row_addr), @@ -274,7 +277,27 @@ static void fsl_ddr_dimm_parameters_edit(fsl_ddr_info_t *pinfo, DIMM_PARM(tdqsq_max_ps), DIMM_PARM(tqhs_ps), #endif - +#ifdef CONFIG_SYS_FSL_DDR4 + DIMM_PARM_HEX(dq_mapping[0]), + DIMM_PARM_HEX(dq_mapping[1]), + DIMM_PARM_HEX(dq_mapping[2]), + DIMM_PARM_HEX(dq_mapping[3]), + DIMM_PARM_HEX(dq_mapping[4]), + DIMM_PARM_HEX(dq_mapping[5]), + DIMM_PARM_HEX(dq_mapping[6]), + DIMM_PARM_HEX(dq_mapping[7]), + DIMM_PARM_HEX(dq_mapping[8]), + DIMM_PARM_HEX(dq_mapping[9]), + DIMM_PARM_HEX(dq_mapping[10]), + DIMM_PARM_HEX(dq_mapping[11]), + DIMM_PARM_HEX(dq_mapping[12]), + DIMM_PARM_HEX(dq_mapping[13]), + DIMM_PARM_HEX(dq_mapping[14]), + DIMM_PARM_HEX(dq_mapping[15]), + DIMM_PARM_HEX(dq_mapping[16]), + DIMM_PARM_HEX(dq_mapping[17]), + DIMM_PARM(dq_mapping_ors), +#endif DIMM_PARM(rank_density), DIMM_PARM(capacity), DIMM_PARM(base_address), @@ -296,6 +319,7 @@ static void print_dimm_parameters(const dimm_params_t *pdimm) DIMM_PARM(primary_sdram_width), DIMM_PARM(ec_sdram_width), DIMM_PARM(registered_dimm), + DIMM_PARM(mirrored_dimm), DIMM_PARM(device_width), DIMM_PARM(n_row_addr), @@ -314,6 +338,7 @@ static void print_dimm_parameters(const dimm_params_t *pdimm) DIMM_PARM(tckmax_ps), DIMM_PARM(caslat_x), + DIMM_PARM_HEX(caslat_x), DIMM_PARM(taa_ps), DIMM_PARM(caslat_x_minus_1), DIMM_PARM(caslat_x_minus_2), @@ -322,6 +347,9 @@ static void print_dimm_parameters(const dimm_params_t *pdimm) DIMM_PARM(trcd_ps), DIMM_PARM(trp_ps), DIMM_PARM(tras_ps), +#if defined(CONFIG_SYS_FSL_DDR4) || defined(CONFIG_SYS_FSL_DDR3) + DIMM_PARM(tfaw_ps), +#endif #ifdef CONFIG_SYS_FSL_DDR4 DIMM_PARM(trfc1_ps), DIMM_PARM(trfc2_ps), @@ -347,6 +375,27 @@ static void print_dimm_parameters(const dimm_params_t *pdimm) DIMM_PARM(tdqsq_max_ps), DIMM_PARM(tqhs_ps), #endif +#ifdef CONFIG_SYS_FSL_DDR4 + DIMM_PARM_HEX(dq_mapping[0]), + DIMM_PARM_HEX(dq_mapping[1]), + DIMM_PARM_HEX(dq_mapping[2]), + DIMM_PARM_HEX(dq_mapping[3]), + DIMM_PARM_HEX(dq_mapping[4]), + DIMM_PARM_HEX(dq_mapping[5]), + DIMM_PARM_HEX(dq_mapping[6]), + DIMM_PARM_HEX(dq_mapping[7]), + DIMM_PARM_HEX(dq_mapping[8]), + DIMM_PARM_HEX(dq_mapping[9]), + DIMM_PARM_HEX(dq_mapping[10]), + DIMM_PARM_HEX(dq_mapping[11]), + DIMM_PARM_HEX(dq_mapping[12]), + DIMM_PARM_HEX(dq_mapping[13]), + DIMM_PARM_HEX(dq_mapping[14]), + DIMM_PARM_HEX(dq_mapping[15]), + DIMM_PARM_HEX(dq_mapping[16]), + DIMM_PARM_HEX(dq_mapping[17]), + DIMM_PARM(dq_mapping_ors), +#endif }; static const unsigned int n_opts = ARRAY_SIZE(options); @@ -463,7 +512,7 @@ static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo, CTRL_OPTIONS_CS(3, odt_rd_cfg), CTRL_OPTIONS_CS(3, odt_wr_cfg), #endif -#if defined(CONFIG_SYS_FSL_DDR3) +#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) CTRL_OPTIONS_CS(0, odt_rtt_norm), CTRL_OPTIONS_CS(0, odt_rtt_wr), #if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) @@ -753,7 +802,7 @@ static void print_memctl_options(const memctl_options_t *popts) CTRL_OPTIONS_CS(3, odt_rd_cfg), CTRL_OPTIONS_CS(3, odt_wr_cfg), #endif -#if defined(CONFIG_SYS_FSL_DDR3) +#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) CTRL_OPTIONS_CS(0, odt_rtt_norm), CTRL_OPTIONS_CS(0, odt_rtt_wr), #if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) @@ -795,6 +844,7 @@ static void print_memctl_options(const memctl_options_t *popts) CTRL_OPTIONS(twot_en), CTRL_OPTIONS(threet_en), CTRL_OPTIONS(registered_dimm_en), + CTRL_OPTIONS(mirrored_dimm), CTRL_OPTIONS(ap_en), CTRL_OPTIONS(x4_en), CTRL_OPTIONS(bstopre), diff --git a/drivers/ddr/fsl/lc_common_dimm_params.c b/drivers/ddr/fsl/lc_common_dimm_params.c index b295344..b12eeb9 100644 --- a/drivers/ddr/fsl/lc_common_dimm_params.c +++ b/drivers/ddr/fsl/lc_common_dimm_params.c @@ -22,7 +22,7 @@ compute_cas_latency(const unsigned int ctrl_num, unsigned int common_caslat; unsigned int caslat_actual; unsigned int retry = 16; - unsigned int tmp; + unsigned int tmp = ~0; const unsigned int mclk_ps = get_memory_clk_period_ps(ctrl_num); #ifdef CONFIG_SYS_FSL_DDR3 const unsigned int taamax = 20000; @@ -31,8 +31,7 @@ compute_cas_latency(const unsigned int ctrl_num, #endif /* compute the common CAS latency supported between slots */ - tmp = dimm_params[0].caslat_x; - for (i = 1; i < number_of_dimms; i++) { + for (i = 0; i < number_of_dimms; i++) { if (dimm_params[i].n_ranks) tmp &= dimm_params[i].caslat_x; } diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c index b72b242..fa22383 100644 --- a/drivers/ddr/fsl/main.c +++ b/drivers/ddr/fsl/main.c @@ -453,7 +453,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step, retval = compute_dimm_parameters( i, spd, pdimm, j); #ifdef CONFIG_SYS_DDR_RAW_TIMING - if (!i && !j && retval) { + if (!j && retval) { printf("SPD error on controller %d! " "Trying fallback to raw timing " "calculation\n", i); diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c index 5beb11b..3b30fa2 100644 --- a/drivers/ddr/fsl/options.c +++ b/drivers/ddr/fsl/options.c @@ -728,7 +728,12 @@ unsigned int populate_memctl_options(int all_dimms_registered, /* Choose ddr controller address mirror mode */ #if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) - popts->mirrored_dimm = pdimm[0].mirrored_dimm; + for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { + if (pdimm[i].n_ranks) { + popts->mirrored_dimm = pdimm[i].mirrored_dimm; + break; + } + } #endif /* Global Timing Parameters. */ diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c index 664081b..ce55aea 100644 --- a/drivers/ddr/fsl/util.c +++ b/drivers/ddr/fsl/util.c @@ -23,12 +23,34 @@ #define ULL_8FS 0xFFFFFFFFULL -u32 fsl_ddr_get_version(void) +u32 fsl_ddr_get_version(unsigned int ctrl_num) { struct ccsr_ddr __iomem *ddr; u32 ver_major_minor_errata; - ddr = (void *)_DDR_ADDR; + switch (ctrl_num) { + case 0: + ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + break; +#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1) + case 1: + ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2) + case 2: + ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3) + case 3: + ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR; + break; +#endif + default: + printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num); + return 0; + } ver_major_minor_errata = (ddr_in32(&ddr->ip_rev1) & 0xFFFF) << 8; ver_major_minor_errata |= (ddr_in32(&ddr->ip_rev2) & 0xFF00) >> 8; @@ -212,7 +234,7 @@ void print_ddr_info(unsigned int start_ctrl) /* Calculate CAS latency based on timing cfg values */ cas_lat = ((ddr_in32(&ddr->timing_cfg_1) >> 16) & 0xf); - if (fsl_ddr_get_version() <= 0x40400) + if (fsl_ddr_get_version(0) <= 0x40400) cas_lat += 1; else cas_lat += 2; diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index fc5ee35..42782cb 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -114,6 +114,9 @@ static u16 i2c_clk_div[50][2] = { #ifndef CONFIG_SYS_MXC_I2C3_SPEED #define CONFIG_SYS_MXC_I2C3_SPEED 100000 #endif +#ifndef CONFIG_SYS_MXC_I2C4_SPEED +#define CONFIG_SYS_MXC_I2C4_SPEED 100000 +#endif #ifndef CONFIG_SYS_MXC_I2C1_SLAVE #define CONFIG_SYS_MXC_I2C1_SLAVE 0 @@ -124,6 +127,9 @@ static u16 i2c_clk_div[50][2] = { #ifndef CONFIG_SYS_MXC_I2C3_SLAVE #define CONFIG_SYS_MXC_I2C3_SLAVE 0 #endif +#ifndef CONFIG_SYS_MXC_I2C4_SLAVE +#define CONFIG_SYS_MXC_I2C4_SLAVE 0 +#endif /* @@ -543,12 +549,17 @@ U_BOOT_I2C_ADAP_COMPLETE(mxc1, mxc_i2c_init, mxc_i2c_probe, mxc_i2c_set_bus_speed, CONFIG_SYS_MXC_I2C2_SPEED, CONFIG_SYS_MXC_I2C2_SLAVE, 1) -#if defined(CONFIG_MX31) || defined(CONFIG_MX35) ||\ - defined(CONFIG_MX51) || defined(CONFIG_MX53) ||\ - defined(CONFIG_MX6) || defined(CONFIG_LS102XA) +#ifdef CONFIG_SYS_I2C_MXC_I2C3 U_BOOT_I2C_ADAP_COMPLETE(mxc2, mxc_i2c_init, mxc_i2c_probe, mxc_i2c_read, mxc_i2c_write, mxc_i2c_set_bus_speed, CONFIG_SYS_MXC_I2C3_SPEED, CONFIG_SYS_MXC_I2C3_SLAVE, 2) #endif +#ifdef CONFIG_SYS_I2C_MXC_I2C4 +U_BOOT_I2C_ADAP_COMPLETE(mxc3, mxc_i2c_init, mxc_i2c_probe, + mxc_i2c_read, mxc_i2c_write, + mxc_i2c_set_bus_speed, + CONFIG_SYS_MXC_I2C4_SPEED, + CONFIG_SYS_MXC_I2C4_SLAVE, 3) +#endif diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 842209a..25630c3 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o +obj-$(CONFIG_FSL_DEBUG_SERVER) += fsl_debug_server.o obj-$(CONFIG_FSL_IIM) += fsl_iim.o obj-$(CONFIG_GPIO_LED) += gpio_led.o obj-$(CONFIG_I2C_EEPROM) += i2c_eeprom.o diff --git a/drivers/misc/fsl_debug_server.c b/drivers/misc/fsl_debug_server.c new file mode 100644 index 0000000..e080fe6 --- /dev/null +++ b/drivers/misc/fsl_debug_server.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/arch-fsl-lsch3/immap_lsch3.h> + +#include <fsl_debug_server.h> + +DECLARE_GLOBAL_DATA_PTR; +static int debug_server_ver_info_maj, debug_server_ver_info_min; + +/** + * Copying Debug Server firmware to DDR + */ +static int debug_server_copy_image(const char *title, u64 image_addr, + u32 image_size, u64 debug_server_ram_addr) +{ + debug("%s copied to address %p\n", title, + (void *)debug_server_ram_addr); + memcpy((void *)debug_server_ram_addr, (void *)image_addr, image_size); + + return 0; +} + +/** + * Debug Server FIT image parser checks if the image is in FIT + * format, verifies integrity of the image and calculates + * raw image address and size values. + * + * Returns 0 if success and -1 if any of the above mentioned + * task fail. + **/ +int debug_server_parse_firmware_fit_image(const void **raw_image_addr, + size_t *raw_image_size) +{ + int format; + void *fit_hdr; + int node_offset; + const void *data; + size_t size; + const char *uname = "firmware"; + char *desc; + char *debug_server_ver_info; + char *debug_server_ver_info_major, *debug_server_ver_info_minor; + + /* Check if the image is in NOR flash */ +#ifdef CONFIG_SYS_DEBUG_SERVER_FW_IN_NOR + fit_hdr = (void *)CONFIG_SYS_DEBUG_SERVER_FW_ADDR; +#else +#error "CONFIG_SYS_DEBUG_SERVER_FW_IN_NOR not defined" +#endif + + /* Check if Image is in FIT format */ + format = genimg_get_format(fit_hdr); + if (format != IMAGE_FORMAT_FIT) { + printf("Error! Not a FIT image\n"); + goto out_error; + } + + if (!fit_check_format(fit_hdr)) { + printf("Error! Bad FIT image format\n"); + goto out_error; + } + + node_offset = fit_image_get_node(fit_hdr, uname); + if (node_offset < 0) { + printf("Error! Can not find %s subimage\n", uname); + goto out_error; + } + + /* Verify Debug Server firmware image */ + if (!fit_image_verify(fit_hdr, node_offset)) { + printf("Error! Bad Debug Server firmware hash"); + goto out_error; + } + + if (fit_get_desc(fit_hdr, node_offset, &desc) < 0) { + printf("Error! Failed to get Debug Server fw description"); + goto out_error; + } + + debug_server_ver_info = strstr(desc, "Version"); + debug_server_ver_info_major = strtok(debug_server_ver_info, "."); + debug_server_ver_info_minor = strtok(NULL, "."); + + debug_server_ver_info_maj = + simple_strtoul(debug_server_ver_info_major, NULL, 10); + debug_server_ver_info_min = + simple_strtoul(debug_server_ver_info_minor, NULL, 10); + + /* Debug server version checking */ + if ((debug_server_ver_info_maj < DEBUG_SERVER_VER_MAJOR) || + (debug_server_ver_info_min < DEBUG_SERVER_VER_MINOR)) { + printf("Debug server FW mismatches the min version required\n"); + printf("Expected:%d.%d, Got %d.%d\n", + DEBUG_SERVER_VER_MAJOR, DEBUG_SERVER_VER_MINOR, + debug_server_ver_info_maj, + debug_server_ver_info_min); + goto out_error; + } + + /* Get address and size of raw image */ + fit_image_get_data(fit_hdr, node_offset, &data, &size); + + *raw_image_addr = data; + *raw_image_size = size; + + return 0; + +out_error: + return -1; +} + +/** + * Return the actual size of the Debug Server private DRAM block. + * + * NOTE: For now this function always returns the minimum required size, + * However, in the future, the actual size may be obtained from an environment + * variable. + */ +unsigned long debug_server_get_dram_block_size(void) +{ + return CONFIG_SYS_DEBUG_SERVER_DRAM_BLOCK_MIN_SIZE; +} + +int debug_server_init(void) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + int error, timeout = CONFIG_SYS_DEBUG_SERVER_TIMEOUT; + int debug_server_boot_status; + u64 debug_server_ram_addr, debug_server_ram_size; + const void *raw_image_addr; + size_t raw_image_size = 0; + + debug("debug_server_init called\n"); + /* + * The Debug Server private DRAM block was already carved at the end of + * DRAM by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE: + */ + debug_server_ram_size = debug_server_get_dram_block_size(); + if (gd->bd->bi_dram[1].start) + debug_server_ram_addr = + gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size; + else + debug_server_ram_addr = + gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; + + error = debug_server_parse_firmware_fit_image(&raw_image_addr, + &raw_image_size); + if (error != 0) + goto out; + + debug("debug server (ram addr = 0x%llx, ram size = 0x%llx)\n", + debug_server_ram_addr, debug_server_ram_size); + /* + * Load the Debug Server FW at the beginning of the Debug Server + * private DRAM block: + */ + debug_server_copy_image("Debug Server Firmware", + (u64)raw_image_addr, raw_image_size, + debug_server_ram_addr); + + /* flush dcache */ + flush_dcache_range((unsigned long)debug_server_ram_addr, + (unsigned long)debug_server_ram_addr + + (unsigned long)debug_server_ram_size); + + /* + * Tell SP that the Debug Server FW is about to be launched. Before that + * populate the following: + * 1. Write the size allocated to SP Memory region into Bits {31:16} of + * SCRATCHRW5. + * 2. Write the start address of the SP memory regions into + * SCRATCHRW5 (Bits {15:0}, contain most significant bits, Bits + * {47:32} of the SP Memory Region physical start address + * (SoC address)) and SCRATCHRW6 (Bits {31:0}). + * 3. To know the Debug Server FW boot status, set bit 0 of SCRATCHRW11 + * to 1. The Debug Server sets this to 0 to indicate a + * successul boot. + * 4. Wakeup SP by writing 0x1F to VSG GIC reg VIGR2. + */ + + /* 512 MB */ + out_le32(&gur->scratchrw[5 - 1], + (u32)((u64)debug_server_ram_addr >> 32) | (0x000D << 16)); + out_le32(&gur->scratchrw[6 - 1], + ((u32)debug_server_ram_addr) & 0xFFFFFFFF); + + out_le32(&gur->scratchrw[11 - 1], DEBUG_SERVER_INIT_STATUS); + /* Allow the changes to reflect in GUR block */ + mb(); + + /* + * Program VGIC to raise an interrupt to SP + */ + out_le32(CONFIG_SYS_FSL_SP_VSG_GIC_VIGR2, 0x1F); + /* Allow the changes to reflect in VIGR2 */ + mb(); + + dmb(); + debug("Polling for Debug server to launch ...\n"); + + while (1) { + debug_server_boot_status = in_le32(&gur->scratchrw[11 - 1]); + if (!(debug_server_boot_status & DEBUG_SERVER_INIT_STATUS_MASK)) + break; + + udelay(1); /* throttle polling */ + if (timeout-- <= 0) + break; + } + + if (timeout <= 0) { + printf("Debug Server FW timed out (boot status: 0x%x)\n", + debug_server_boot_status); + error = -ETIMEDOUT; + goto out; + } + + if (debug_server_boot_status & DEBUG_SERVER_INIT_STATUS_MASK) { + printf("Debug server FW error'ed out (boot status: 0x%x)\n", + debug_server_boot_status); + error = -ENODEV; + goto out; + } + + printf("Debug server booted\n"); + printf("Detected firmware %d.%d, (boot status: 0x0%x)\n", + debug_server_ver_info_maj, debug_server_ver_info_min, + debug_server_boot_status); + +out: + if (error != 0) + debug_server_boot_status = -error; + else + debug_server_boot_status = 0; + + return debug_server_boot_status; +} + diff --git a/drivers/misc/fsl_ifc.c b/drivers/misc/fsl_ifc.c index 3902e9f..a33efdb 100644 --- a/drivers/misc/fsl_ifc.c +++ b/drivers/misc/fsl_ifc.c @@ -168,4 +168,25 @@ void init_final_memctl_regs(void) #ifdef CONFIG_SYS_CSPR0_FINAL set_ifc_cspr(IFC_CS0, CONFIG_SYS_CSPR0_FINAL); #endif +#ifdef CONFIG_SYS_AMASK0_FINAL + set_ifc_amask(IFC_CS0, CONFIG_SYS_AMASK0); +#endif +#ifdef CONFIG_SYS_CSPR1_FINAL + set_ifc_cspr(IFC_CS1, CONFIG_SYS_CSPR1_FINAL); +#endif +#ifdef CONFIG_SYS_AMASK1_FINAL + set_ifc_amask(IFC_CS1, CONFIG_SYS_AMASK1_FINAL); +#endif +#ifdef CONFIG_SYS_CSPR2_FINAL + set_ifc_cspr(IFC_CS2, CONFIG_SYS_CSPR2_FINAL); +#endif +#ifdef CONFIG_SYS_AMASK2_FINAL + set_ifc_amask(IFC_CS2, CONFIG_SYS_AMASK2); +#endif +#ifdef CONFIG_SYS_CSPR3_FINAL + set_ifc_cspr(IFC_CS3, CONFIG_SYS_CSPR3_FINAL); +#endif +#ifdef CONFIG_SYS_AMASK3_FINAL + set_ifc_amask(IFC_CS3, CONFIG_SYS_AMASK3); +#endif } diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index db4d251..10ec216 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -105,7 +105,8 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) else if (cmd->resp_type & MMC_RSP_PRESENT) xfertyp |= XFERTYP_RSPTYP_48; -#if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) || defined(CONFIG_LS102XA) +#if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) || \ + defined(CONFIG_LS102XA) || defined(CONFIG_LS2085A) if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) xfertyp |= XFERTYP_CMDTYP_ABORT; #endif @@ -183,7 +184,9 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) int timeout; struct fsl_esdhc_cfg *cfg = mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; - +#ifdef CONFIG_LS2085A + dma_addr_t addr; +#endif uint wml_value; wml_value = data->blocksize/4; @@ -194,8 +197,16 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO +#ifdef CONFIG_LS2085A + addr = virt_to_phys((void *)(data->dest)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); +#else esdhc_write32(®s->dsaddr, (u32)data->dest); #endif +#endif } else { #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO flush_dcache_range((ulong)data->src, @@ -212,8 +223,16 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, wml_value << 16); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO +#ifdef CONFIG_LS2085A + addr = virt_to_phys((void *)(data->src)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); +#else esdhc_write32(®s->dsaddr, (u32)data->src); #endif +#endif } esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); @@ -259,10 +278,23 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) static void check_and_invalidate_dcache_range (struct mmc_cmd *cmd, struct mmc_data *data) { +#ifdef CONFIG_LS2085A + unsigned start = 0; +#else unsigned start = (unsigned)data->dest ; +#endif unsigned size = roundup(ARCH_DMA_MINALIGN, data->blocks*data->blocksize); unsigned end = start+size ; +#ifdef CONFIG_LS2085A + dma_addr_t addr; + + addr = virt_to_phys((void *)(data->dest)); + if (upper_32_bits(addr)) + printf("Error found for upper 32 bits\n"); + else + start = lower_32_bits(addr); +#endif invalidate_dcache_range(start, end); } #endif diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 7903eeb..79fa88b 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -46,7 +46,7 @@ struct fsl_ifc_ctrl { struct fsl_ifc_mtd *chips[MAX_BANKS]; /* device info */ - struct fsl_ifc *regs; + struct fsl_ifc regs; uint8_t __iomem *addr; /* Address of assigned IFC buffer */ unsigned int cs_nand; /* On which chipsel NAND is connected */ unsigned int page; /* Last page written to / read from */ @@ -225,7 +225,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) struct nand_chip *chip = mtd->priv; struct fsl_ifc_mtd *priv = chip->priv; struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; int buf_num; ctrl->page = page_addr; @@ -289,10 +289,10 @@ static int fsl_ifc_run_command(struct mtd_info *mtd) struct nand_chip *chip = mtd->priv; struct fsl_ifc_mtd *priv = chip->priv; struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; u32 time_start; - u32 eccstat[4] = {0}; + u32 eccstat[8] = {0}; int i; /* set the chip select for NAND Transaction */ @@ -325,8 +325,15 @@ static int fsl_ifc_run_command(struct mtd_info *mtd) int sector = bufnum * chip->ecc.steps; int sector_end = sector + chip->ecc.steps - 1; - for (i = sector / 4; i <= sector_end / 4; i++) + for (i = sector / 4; i <= sector_end / 4; i++) { + if (i >= ARRAY_SIZE(eccstat)) { + printf("%s: eccstat too small for %d\n", + __func__, i); + return -EIO; + } + eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); + } for (i = sector; i <= sector_end; i++) { errors = check_read_ecc(mtd, ctrl, eccstat, i); @@ -362,7 +369,7 @@ static void fsl_ifc_do_read(struct nand_chip *chip, { struct fsl_ifc_mtd *priv = chip->priv; struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; /* Program FIR/IFC_NAND_FCR0 for Small/Large page */ if (mtd->writesize > 512) { @@ -400,7 +407,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, struct nand_chip *chip = mtd->priv; struct fsl_ifc_mtd *priv = chip->priv; struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; /* clear the read buffer */ ctrl->read_bytes = 0; @@ -690,7 +697,7 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) { struct fsl_ifc_mtd *priv = chip->priv; struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; + struct fsl_ifc_runtime *ifc = ctrl->regs.rregs; u32 nand_fsr; if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) @@ -747,24 +754,33 @@ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, static void fsl_ifc_ctrl_init(void) { + uint32_t ver = 0; ifc_ctrl = kzalloc(sizeof(*ifc_ctrl), GFP_KERNEL); if (!ifc_ctrl) return; - ifc_ctrl->regs = IFC_BASE_ADDR; + ifc_ctrl->regs.gregs = IFC_FCM_BASE_ADDR; + + ver = ifc_in32(&ifc_ctrl->regs.gregs->ifc_rev); + if (ver >= FSL_IFC_V2_0_0) + ifc_ctrl->regs.rregs = + (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET; + else + ifc_ctrl->regs.rregs = + (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET; /* clear event registers */ - ifc_out32(&ifc_ctrl->regs->ifc_nand.nand_evter_stat, ~0U); - ifc_out32(&ifc_ctrl->regs->ifc_nand.pgrdcmpl_evt_stat, ~0U); + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_stat, ~0U); + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.pgrdcmpl_evt_stat, ~0U); /* Enable error and event for any detected errors */ - ifc_out32(&ifc_ctrl->regs->ifc_nand.nand_evter_en, + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.nand_evter_en, IFC_NAND_EVTER_EN_OPC_EN | IFC_NAND_EVTER_EN_PGRDCMPL_EN | IFC_NAND_EVTER_EN_FTOER_EN | IFC_NAND_EVTER_EN_WPER_EN); - ifc_out32(&ifc_ctrl->regs->ifc_nand.ncfgr, 0x0); + ifc_out32(&ifc_ctrl->regs.rregs->ifc_nand.ncfgr, 0x0); } static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) @@ -773,7 +789,7 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) static int fsl_ifc_sram_init(uint32_t ver) { - struct fsl_ifc *ifc = ifc_ctrl->regs; + struct fsl_ifc_runtime *ifc = ifc_ctrl->regs.rregs; uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0; uint32_t ncfgr = 0; u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; @@ -799,13 +815,13 @@ static int fsl_ifc_sram_init(uint32_t ver) cs = ifc_ctrl->cs_nand >> IFC_NAND_CSEL_SHIFT; /* Save CSOR and CSOR_ext */ - csor = ifc_in32(&ifc_ctrl->regs->csor_cs[cs].csor); - csor_ext = ifc_in32(&ifc_ctrl->regs->csor_cs[cs].csor_ext); + csor = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor); + csor_ext = ifc_in32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext); /* chage PageSize 8K and SpareSize 1K*/ csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000; - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor, csor_8k); - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, 0x0000400); + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor_8k); + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, 0x0000400); /* READID */ ifc_out32(&ifc->ifc_nand.nand_fir0, @@ -845,8 +861,8 @@ static int fsl_ifc_sram_init(uint32_t ver) ifc_out32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status); /* Restore CSOR and CSOR_ext */ - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor, csor); - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext); + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor, csor); + ifc_out32(&ifc_ctrl->regs.gregs->csor_cs[cs].csor_ext, csor_ext); return 0; } @@ -857,6 +873,7 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr) struct nand_chip *nand; struct fsl_ifc_mtd *priv; struct nand_ecclayout *layout; + struct fsl_ifc_fcm *gregs = NULL; uint32_t cspr = 0, csor = 0, ver = 0; int ret = 0; @@ -872,14 +889,15 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr) priv->ctrl = ifc_ctrl; priv->vbase = addr; + gregs = ifc_ctrl->regs.gregs; /* Find which chip select it is connected to. */ for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { phys_addr_t phys_addr = virt_to_phys(addr); - cspr = ifc_in32(&ifc_ctrl->regs->cspr_cs[priv->bank].cspr); - csor = ifc_in32(&ifc_ctrl->regs->csor_cs[priv->bank].csor); + cspr = ifc_in32(&gregs->cspr_cs[priv->bank].cspr); + csor = ifc_in32(&gregs->csor_cs[priv->bank].csor); if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND && (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr)) { @@ -998,7 +1016,7 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr) nand->ecc.mode = NAND_ECC_SOFT; } - ver = ifc_in32(&ifc_ctrl->regs->ifc_rev); + ver = ifc_in32(&gregs->ifc_rev); if (ver >= FSL_IFC_V1_1_0) ret = fsl_ifc_sram_init(ver); if (ret) diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c index fb827c5..fccbfb5 100644 --- a/drivers/mtd/nand/fsl_ifc_spl.c +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -48,11 +48,25 @@ static inline int check_read_ecc(uchar *buf, u32 *eccstat, return 0; } +static inline struct fsl_ifc_runtime *runtime_regs_address(void) +{ + struct fsl_ifc regs = {(void *)CONFIG_SYS_IFC_ADDR, NULL}; + int ver = 0; + + ver = ifc_in32(®s.gregs->ifc_rev); + if (ver >= FSL_IFC_V2_0_0) + regs.rregs = (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_64KOFFSET; + else + regs.rregs = (void *)CONFIG_SYS_IFC_ADDR + IFC_RREGS_4KOFFSET; + + return regs.rregs; +} + static inline void nand_wait(uchar *buf, int bufnum, int page_size) { - struct fsl_ifc *ifc = IFC_BASE_ADDR; + struct fsl_ifc_runtime *ifc = runtime_regs_address(); u32 status; - u32 eccstat[4]; + u32 eccstat[8]; int bufperpage = page_size / 512; int bufnum_end, i; @@ -90,7 +104,8 @@ static inline int bad_block(uchar *marker, int port_size) int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) { - struct fsl_ifc *ifc = IFC_BASE_ADDR; + struct fsl_ifc_fcm *gregs = (void *)CONFIG_SYS_IFC_ADDR; + struct fsl_ifc_runtime *ifc = NULL; uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; int page_size; int port_size; @@ -107,6 +122,8 @@ int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) int pg_no; uchar *dst = vdst; + ifc = runtime_regs_address(); + /* Get NAND Flash configuration */ csor = CONFIG_SYS_NAND_CSOR; cspr = CONFIG_SYS_NAND_CSPR; @@ -130,7 +147,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) bad_marker = 5; } - ver = ifc_in32(&ifc->ifc_rev); + ver = ifc_in32(&gregs->ifc_rev); if (ver >= FSL_IFC_V2_0_0) bufnum_mask = (bufnum_mask * 2) + 1; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f24443d..150470c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -69,4 +69,6 @@ obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \ xilinx_ll_temac_fifo.o xilinx_ll_temac_sdma.o obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/ +obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/ +obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o obj-$(CONFIG_VSC9953) += vsc9953.o diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 2d66690..96e6bb0 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -2174,7 +2174,7 @@ e1000_copper_link_preconfig(struct e1000_hw *hw) DEBUGOUT("Error, did not detect valid phy.\n"); return ret_val; } - DEBUGOUT("Phy ID = %x \n", hw->phy_id); + DEBUGOUT("Phy ID = %x\n", hw->phy_id); /* Set PHY to class A mode (if necessary) */ ret_val = e1000_set_phy_mode(hw); @@ -3485,11 +3485,11 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw) * some "sticky" (latched) bits. */ if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error \n"); + DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } if (e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) { - DEBUGOUT("PHY Read Error \n"); + DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } @@ -5152,7 +5152,7 @@ e1000_poll(struct eth_device *nic) if (!(le32_to_cpu(rd->status)) & E1000_RXD_STAT_DD) return 0; - /*DEBUGOUT("recv: packet len=%d \n", rd->length); */ + /* DEBUGOUT("recv: packet len=%d\n", rd->length); */ /* Packet received, make sure the data are re-loaded from RAM. */ len = le32_to_cpu(rd->length); invalidate_dcache_range((unsigned long)packet, diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c index 55e76a7..d7a37f3 100644 --- a/drivers/net/fm/eth.c +++ b/drivers/net/fm/eth.c @@ -15,7 +15,7 @@ #include <phy.h> #include <asm/fsl_dtsec.h> #include <asm/fsl_tgec.h> -#include <asm/fsl_memac.h> +#include <fsl_memac.h> #include "fm.h" diff --git a/drivers/net/fm/memac.c b/drivers/net/fm/memac.c index 60e898c..81a64bf 100644 --- a/drivers/net/fm/memac.c +++ b/drivers/net/fm/memac.c @@ -12,7 +12,7 @@ #include <phy.h> #include <asm/types.h> #include <asm/io.h> -#include <asm/fsl_memac.h> +#include <fsl_memac.h> #include "fm.h" diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c index a155d89..4ab78e6 100644 --- a/drivers/net/fm/memac_phy.c +++ b/drivers/net/fm/memac_phy.c @@ -10,9 +10,28 @@ #include <miiphy.h> #include <phy.h> #include <asm/io.h> -#include <asm/fsl_memac.h> +#include <fsl_memac.h> #include <fm_eth.h> +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN +#define memac_out_32(a, v) out_le32(a, v) +#define memac_clrbits_32(a, v) clrbits_le32(a, v) +#define memac_setbits_32(a, v) setbits_le32(a, v) +#else +#define memac_out_32(a, v) out_be32(a, v) +#define memac_clrbits_32(a, v) clrbits_be32(a, v) +#define memac_setbits_32(a, v) setbits_be32(a, v) +#endif + +static u32 memac_in_32(u32 *reg) +{ +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN + return in_le32(reg); +#else + return in_be32(reg); +#endif +} + /* * Write value to the PHY for this device to the register at regnum, waiting * until the write is done before it returns. All PHY configuration has to be @@ -28,31 +47,31 @@ int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr, if (dev_addr == MDIO_DEVAD_NONE) { c45 = 0; /* clause 22 */ dev_addr = regnum & 0x1f; - clrbits_be32(®s->mdio_stat, MDIO_STAT_ENC); + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); } else - setbits_be32(®s->mdio_stat, MDIO_STAT_ENC); + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); /* Wait till the bus is free */ - while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) ; /* Set the port and dev addr */ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); - out_be32(®s->mdio_ctl, mdio_ctl); + memac_out_32(®s->mdio_ctl, mdio_ctl); /* Set the register address */ if (c45) - out_be32(®s->mdio_addr, regnum & 0xffff); + memac_out_32(®s->mdio_addr, regnum & 0xffff); /* Wait till the bus is free */ - while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) ; /* Write the value to the register */ - out_be32(®s->mdio_data, MDIO_DATA(value)); + memac_out_32(®s->mdio_data, MDIO_DATA(value)); /* Wait till the MDIO write is complete */ - while ((in_be32(®s->mdio_data)) & MDIO_DATA_BSY) + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) ; return 0; @@ -75,39 +94,39 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr, return 0xffff; c45 = 0; /* clause 22 */ dev_addr = regnum & 0x1f; - clrbits_be32(®s->mdio_stat, MDIO_STAT_ENC); + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); } else - setbits_be32(®s->mdio_stat, MDIO_STAT_ENC); + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); /* Wait till the bus is free */ - while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) ; /* Set the Port and Device Addrs */ mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); - out_be32(®s->mdio_ctl, mdio_ctl); + memac_out_32(®s->mdio_ctl, mdio_ctl); /* Set the register address */ if (c45) - out_be32(®s->mdio_addr, regnum & 0xffff); + memac_out_32(®s->mdio_addr, regnum & 0xffff); /* Wait till the bus is free */ - while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY) + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) ; /* Initiate the read */ mdio_ctl |= MDIO_CTL_READ; - out_be32(®s->mdio_ctl, mdio_ctl); + memac_out_32(®s->mdio_ctl, mdio_ctl); /* Wait till the MDIO write is complete */ - while ((in_be32(®s->mdio_data)) & MDIO_DATA_BSY) + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) ; /* Return all Fs if nothing was there */ - if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) + if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) return 0xffff; - return in_be32(®s->mdio_data) & 0xffff; + return memac_in_32(®s->mdio_data) & 0xffff; } int memac_mdio_reset(struct mii_dev *bus) @@ -143,8 +162,9 @@ int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info) * like T2080QDS, this bit default is '0', which leads to MDIO failure * on XAUI PHY, so set this bit definitely. */ - setbits_be32(&((struct memac_mdio_controller *)info->regs)->mdio_stat, - MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); + memac_setbits_32( + &((struct memac_mdio_controller *)info->regs)->mdio_stat, + MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); return mdio_register(bus); } diff --git a/drivers/net/fsl-mc/Makefile b/drivers/net/fsl-mc/Makefile index 206ac6b..7563a5f 100644 --- a/drivers/net/fsl-mc/Makefile +++ b/drivers/net/fsl-mc/Makefile @@ -7,4 +7,8 @@ # Layerscape MC driver obj-y += mc.o \ mc_sys.o \ - dpmng.o + dpmng.o \ + dprc.o \ + dpbp.o \ + dpni.o +obj-y += dpio/ diff --git a/drivers/net/fsl-mc/dpbp.c b/drivers/net/fsl-mc/dpbp.c new file mode 100644 index 0000000..3853e58 --- /dev/null +++ b/drivers/net/fsl-mc/dpbp.c @@ -0,0 +1,102 @@ +/* + * Freescale Layerscape MC I/O wrapper + * + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. + * Author: German Rivera <German.Rivera@freescale.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <fsl-mc/fsl_mc_sys.h> +#include <fsl-mc/fsl_mc_cmd.h> +#include <fsl-mc/fsl_dpbp.h> + +int dpbp_open(struct fsl_mc_io *mc_io, int dpbp_id, uint16_t *token) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPBP_CMDID_OPEN, + MC_CMD_PRI_LOW, 0); + DPBP_CMD_OPEN(cmd, dpbp_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + + return err; +} + +int dpbp_close(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLOSE, MC_CMD_PRI_HIGH, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpbp_enable(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPBP_CMDID_ENABLE, MC_CMD_PRI_LOW, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpbp_disable(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpbp_reset(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpbp_get_attributes(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpbp_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_ATTR, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPBP_RSP_GET_ATTRIBUTES(cmd, attr); + + return 0; +} diff --git a/drivers/net/fsl-mc/dpio/Makefile b/drivers/net/fsl-mc/dpio/Makefile new file mode 100644 index 0000000..1ccefc0 --- /dev/null +++ b/drivers/net/fsl-mc/dpio/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2014 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# Layerscape MC DPIO driver +obj-y += dpio.o \ + qbman_portal.o diff --git a/drivers/net/fsl-mc/dpio/dpio.c b/drivers/net/fsl-mc/dpio/dpio.c new file mode 100644 index 0000000..b07eff7 --- /dev/null +++ b/drivers/net/fsl-mc/dpio/dpio.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013-2015 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <fsl-mc/fsl_mc_sys.h> +#include <fsl-mc/fsl_mc_cmd.h> +#include <fsl-mc/fsl_dpio.h> + +int dpio_open(struct fsl_mc_io *mc_io, int dpio_id, uint16_t *token) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_OPEN, + MC_CMD_PRI_LOW, 0); + DPIO_CMD_OPEN(cmd, dpio_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + + return 0; +} + +int dpio_close(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_CLOSE, + MC_CMD_PRI_HIGH, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpio_enable(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_ENABLE, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpio_disable(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_DISABLE, + MC_CMD_PRI_LOW, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpio_reset(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_RESET, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpio_get_attributes(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpio_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_GET_ATTR, + MC_CMD_PRI_LOW, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPIO_RSP_GET_ATTR(cmd, attr); + + return 0; +} diff --git a/drivers/net/fsl-mc/dpio/qbman_portal.c b/drivers/net/fsl-mc/dpio/qbman_portal.c new file mode 100644 index 0000000..dd2a7de --- /dev/null +++ b/drivers/net/fsl-mc/dpio/qbman_portal.c @@ -0,0 +1,593 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "qbman_portal.h" + +/* QBMan portal management command codes */ +#define QBMAN_MC_ACQUIRE 0x30 +#define QBMAN_WQCHAN_CONFIGURE 0x46 + +/* CINH register offsets */ +#define QBMAN_CINH_SWP_EQAR 0x8c0 +#define QBMAN_CINH_SWP_DCAP 0xac0 +#define QBMAN_CINH_SWP_SDQCR 0xb00 +#define QBMAN_CINH_SWP_RAR 0xcc0 + +/* CENA register offsets */ +#define QBMAN_CENA_SWP_EQCR(n) (0x000 + ((uint32_t)(n) << 6)) +#define QBMAN_CENA_SWP_DQRR(n) (0x200 + ((uint32_t)(n) << 6)) +#define QBMAN_CENA_SWP_RCR(n) (0x400 + ((uint32_t)(n) << 6)) +#define QBMAN_CENA_SWP_CR 0x600 +#define QBMAN_CENA_SWP_RR(vb) (0x700 + ((uint32_t)(vb) >> 1)) +#define QBMAN_CENA_SWP_VDQCR 0x780 + +/* Reverse mapping of QBMAN_CENA_SWP_DQRR() */ +#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)p & 0xff) >> 6) + +/*******************************/ +/* Pre-defined attribute codes */ +/*******************************/ + +struct qb_attr_code code_generic_verb = QB_CODE(0, 0, 7); +struct qb_attr_code code_generic_rslt = QB_CODE(0, 8, 8); + +/*************************/ +/* SDQCR attribute codes */ +/*************************/ + +/* we put these here because at least some of them are required by + * qbman_swp_init() */ +struct qb_attr_code code_sdqcr_dct = QB_CODE(0, 24, 2); +struct qb_attr_code code_sdqcr_fc = QB_CODE(0, 29, 1); +struct qb_attr_code code_sdqcr_tok = QB_CODE(0, 16, 8); +#define CODE_SDQCR_DQSRC(n) QB_CODE(0, n, 1) +enum qbman_sdqcr_dct { + qbman_sdqcr_dct_null = 0, + qbman_sdqcr_dct_prio_ics, + qbman_sdqcr_dct_active_ics, + qbman_sdqcr_dct_active +}; +enum qbman_sdqcr_fc { + qbman_sdqcr_fc_one = 0, + qbman_sdqcr_fc_up_to_3 = 1 +}; + +/*********************************/ +/* Portal constructor/destructor */ +/*********************************/ + +/* Software portals should always be in the power-on state when we initialise, + * due to the CCSR-based portal reset functionality that MC has. */ +struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) +{ + int ret; + struct qbman_swp *p = kmalloc(sizeof(*p), GFP_KERNEL); + + if (!p) + return NULL; + p->desc = d; +#ifdef QBMAN_CHECKING + p->mc.check = swp_mc_can_start; +#endif + p->mc.valid_bit = QB_VALID_BIT; + p->sdq = 0; + qb_attr_code_encode(&code_sdqcr_dct, &p->sdq, qbman_sdqcr_dct_prio_ics); + qb_attr_code_encode(&code_sdqcr_fc, &p->sdq, qbman_sdqcr_fc_up_to_3); + qb_attr_code_encode(&code_sdqcr_tok, &p->sdq, 0xbb); + p->vdq.busy = 0; /* TODO: convert to atomic_t */ + p->vdq.valid_bit = QB_VALID_BIT; + p->dqrr.next_idx = 0; + p->dqrr.valid_bit = QB_VALID_BIT; + ret = qbman_swp_sys_init(&p->sys, d); + if (ret) { + free(p); + printf("qbman_swp_sys_init() failed %d\n", ret); + return NULL; + } + qbman_cinh_write(&p->sys, QBMAN_CINH_SWP_SDQCR, p->sdq); + return p; +} + +/***********************/ +/* Management commands */ +/***********************/ + +/* + * Internal code common to all types of management commands. + */ + +void *qbman_swp_mc_start(struct qbman_swp *p) +{ + void *ret; +#ifdef QBMAN_CHECKING + BUG_ON(p->mc.check != swp_mc_can_start); +#endif + ret = qbman_cena_write_start(&p->sys, QBMAN_CENA_SWP_CR); +#ifdef QBMAN_CHECKING + if (!ret) + p->mc.check = swp_mc_can_submit; +#endif + return ret; +} + +void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb) +{ + uint32_t *v = cmd; +#ifdef QBMAN_CHECKING + BUG_ON(!p->mc.check != swp_mc_can_submit); +#endif + lwsync(); + /* TBD: "|=" is going to hurt performance. Need to move as many fields + * out of word zero, and for those that remain, the "OR" needs to occur + * at the caller side. This debug check helps to catch cases where the + * caller wants to OR but has forgotten to do so. */ + BUG_ON((*v & cmd_verb) != *v); + *v = cmd_verb | p->mc.valid_bit; + qbman_cena_write_complete(&p->sys, QBMAN_CENA_SWP_CR, cmd); + /* TODO: add prefetch support for GPP */ +#ifdef QBMAN_CHECKING + p->mc.check = swp_mc_can_poll; +#endif +} + +void *qbman_swp_mc_result(struct qbman_swp *p) +{ + uint32_t *ret, verb; +#ifdef QBMAN_CHECKING + BUG_ON(p->mc.check != swp_mc_can_poll); +#endif + ret = qbman_cena_read(&p->sys, QBMAN_CENA_SWP_RR(p->mc.valid_bit)); + /* Remove the valid-bit - command completed iff the rest is non-zero */ + verb = ret[0] & ~QB_VALID_BIT; + if (!verb) + return NULL; +#ifdef QBMAN_CHECKING + p->mc.check = swp_mc_can_start; +#endif + p->mc.valid_bit ^= QB_VALID_BIT; + return ret; +} + +/***********/ +/* Enqueue */ +/***********/ + +/* These should be const, eventually */ +static struct qb_attr_code code_eq_cmd = QB_CODE(0, 0, 2); +static struct qb_attr_code code_eq_orp_en = QB_CODE(0, 2, 1); +static struct qb_attr_code code_eq_tgt_id = QB_CODE(2, 0, 24); +/* static struct qb_attr_code code_eq_tag = QB_CODE(3, 0, 32); */ +static struct qb_attr_code code_eq_qd_en = QB_CODE(0, 4, 1); +static struct qb_attr_code code_eq_qd_bin = QB_CODE(4, 0, 16); +static struct qb_attr_code code_eq_qd_pri = QB_CODE(4, 16, 4); +static struct qb_attr_code code_eq_rsp_stash = QB_CODE(5, 16, 1); +static struct qb_attr_code code_eq_rsp_lo = QB_CODE(6, 0, 32); +static struct qb_attr_code code_eq_rsp_hi = QB_CODE(7, 0, 32); + +enum qbman_eq_cmd_e { + /* No enqueue, primarily for plugging ORP gaps for dropped frames */ + qbman_eq_cmd_empty, + /* DMA an enqueue response once complete */ + qbman_eq_cmd_respond, + /* DMA an enqueue response only if the enqueue fails */ + qbman_eq_cmd_respond_reject +}; + +void qbman_eq_desc_clear(struct qbman_eq_desc *d) +{ + memset(d, 0, sizeof(*d)); +} + +void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success) +{ + uint32_t *cl = qb_cl(d); + + qb_attr_code_encode(&code_eq_orp_en, cl, 0); + qb_attr_code_encode(&code_eq_cmd, cl, + respond_success ? qbman_eq_cmd_respond : + qbman_eq_cmd_respond_reject); +} + +void qbman_eq_desc_set_response(struct qbman_eq_desc *d, + dma_addr_t storage_phys, + int stash) +{ + uint32_t *cl = qb_cl(d); + + qb_attr_code_encode(&code_eq_rsp_lo, cl, lower32(storage_phys)); + qb_attr_code_encode(&code_eq_rsp_hi, cl, upper32(storage_phys)); + qb_attr_code_encode(&code_eq_rsp_stash, cl, !!stash); +} + + +void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, uint32_t qdid, + uint32_t qd_bin, uint32_t qd_prio) +{ + uint32_t *cl = qb_cl(d); + + qb_attr_code_encode(&code_eq_qd_en, cl, 1); + qb_attr_code_encode(&code_eq_tgt_id, cl, qdid); + qb_attr_code_encode(&code_eq_qd_bin, cl, qd_bin); + qb_attr_code_encode(&code_eq_qd_pri, cl, qd_prio); +} + +#define EQAR_IDX(eqar) ((eqar) & 0x7) +#define EQAR_VB(eqar) ((eqar) & 0x80) +#define EQAR_SUCCESS(eqar) ((eqar) & 0x100) + +int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d, + const struct qbman_fd *fd) +{ + uint32_t *p; + const uint32_t *cl = qb_cl(d); + uint32_t eqar = qbman_cinh_read(&s->sys, QBMAN_CINH_SWP_EQAR); + debug("EQAR=%08x\n", eqar); + if (!EQAR_SUCCESS(eqar)) + return -EBUSY; + p = qbman_cena_write_start(&s->sys, + QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar))); + word_copy(&p[1], &cl[1], 7); + word_copy(&p[8], fd, sizeof(*fd) >> 2); + lwsync(); + /* Set the verb byte, have to substitute in the valid-bit */ + p[0] = cl[0] | EQAR_VB(eqar); + qbman_cena_write_complete(&s->sys, + QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)), + p); + return 0; +} + +/***************************/ +/* Volatile (pull) dequeue */ +/***************************/ + +/* These should be const, eventually */ +static struct qb_attr_code code_pull_dct = QB_CODE(0, 0, 2); +static struct qb_attr_code code_pull_dt = QB_CODE(0, 2, 2); +static struct qb_attr_code code_pull_rls = QB_CODE(0, 4, 1); +static struct qb_attr_code code_pull_stash = QB_CODE(0, 5, 1); +static struct qb_attr_code code_pull_numframes = QB_CODE(0, 8, 4); +static struct qb_attr_code code_pull_token = QB_CODE(0, 16, 8); +static struct qb_attr_code code_pull_dqsource = QB_CODE(1, 0, 24); +static struct qb_attr_code code_pull_rsp_lo = QB_CODE(2, 0, 32); +static struct qb_attr_code code_pull_rsp_hi = QB_CODE(3, 0, 32); + +enum qb_pull_dt_e { + qb_pull_dt_channel, + qb_pull_dt_workqueue, + qb_pull_dt_framequeue +}; + +void qbman_pull_desc_clear(struct qbman_pull_desc *d) +{ + memset(d, 0, sizeof(*d)); +} + +void qbman_pull_desc_set_storage(struct qbman_pull_desc *d, + struct ldpaa_dq *storage, + dma_addr_t storage_phys, + int stash) +{ + uint32_t *cl = qb_cl(d); + + /* Squiggle the pointer 'storage' into the extra 2 words of the + * descriptor (which aren't copied to the hw command) */ + *(void **)&cl[4] = storage; + if (!storage) { + qb_attr_code_encode(&code_pull_rls, cl, 0); + return; + } + qb_attr_code_encode(&code_pull_rls, cl, 1); + qb_attr_code_encode(&code_pull_stash, cl, !!stash); + qb_attr_code_encode(&code_pull_rsp_lo, cl, lower32(storage_phys)); + qb_attr_code_encode(&code_pull_rsp_hi, cl, upper32(storage_phys)); +} + +void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, uint8_t numframes) +{ + uint32_t *cl = qb_cl(d); + + BUG_ON(!numframes || (numframes > 16)); + qb_attr_code_encode(&code_pull_numframes, cl, + (uint32_t)(numframes - 1)); +} + +void qbman_pull_desc_set_token(struct qbman_pull_desc *d, uint8_t token) +{ + uint32_t *cl = qb_cl(d); + + qb_attr_code_encode(&code_pull_token, cl, token); +} + +void qbman_pull_desc_set_fq(struct qbman_pull_desc *d, uint32_t fqid) +{ + uint32_t *cl = qb_cl(d); + + qb_attr_code_encode(&code_pull_dct, cl, 1); + qb_attr_code_encode(&code_pull_dt, cl, qb_pull_dt_framequeue); + qb_attr_code_encode(&code_pull_dqsource, cl, fqid); +} + +int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d) +{ + uint32_t *p; + uint32_t *cl = qb_cl(d); + + /* TODO: convert to atomic_t */ + if (s->vdq.busy) + return -EBUSY; + s->vdq.busy = 1; + s->vdq.storage = *(void **)&cl[4]; + s->vdq.token = qb_attr_code_decode(&code_pull_token, cl); + p = qbman_cena_write_start(&s->sys, QBMAN_CENA_SWP_VDQCR); + word_copy(&p[1], &cl[1], 3); + lwsync(); + /* Set the verb byte, have to substitute in the valid-bit */ + p[0] = cl[0] | s->vdq.valid_bit; + s->vdq.valid_bit ^= QB_VALID_BIT; + qbman_cena_write_complete(&s->sys, QBMAN_CENA_SWP_VDQCR, p); + return 0; +} + +/****************/ +/* Polling DQRR */ +/****************/ + +static struct qb_attr_code code_dqrr_verb = QB_CODE(0, 0, 8); +static struct qb_attr_code code_dqrr_response = QB_CODE(0, 0, 7); +static struct qb_attr_code code_dqrr_stat = QB_CODE(0, 8, 8); + +#define QBMAN_DQRR_RESPONSE_DQ 0x60 +#define QBMAN_DQRR_RESPONSE_FQRN 0x21 +#define QBMAN_DQRR_RESPONSE_FQRNI 0x22 +#define QBMAN_DQRR_RESPONSE_FQPN 0x24 +#define QBMAN_DQRR_RESPONSE_FQDAN 0x25 +#define QBMAN_DQRR_RESPONSE_CDAN 0x26 +#define QBMAN_DQRR_RESPONSE_CSCN_MEM 0x27 +#define QBMAN_DQRR_RESPONSE_CGCU 0x28 +#define QBMAN_DQRR_RESPONSE_BPSCN 0x29 +#define QBMAN_DQRR_RESPONSE_CSCN_WQ 0x2a + + +/* NULL return if there are no unconsumed DQRR entries. Returns a DQRR entry + * only once, so repeated calls can return a sequence of DQRR entries, without + * requiring they be consumed immediately or in any particular order. */ +const struct ldpaa_dq *qbman_swp_dqrr_next(struct qbman_swp *s) +{ + uint32_t verb; + uint32_t response_verb; + const struct ldpaa_dq *dq = qbman_cena_read(&s->sys, + QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); + const uint32_t *p = qb_cl(dq); + + verb = qb_attr_code_decode(&code_dqrr_verb, p); + /* If the valid-bit isn't of the expected polarity, nothing there */ + if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) { + qbman_cena_invalidate_prefetch(&s->sys, + QBMAN_CENA_SWP_DQRR( + s->dqrr.next_idx)); + return NULL; + } + /* There's something there. Move "next_idx" attention to the next ring + * entry (and prefetch it) before returning what we found. */ + s->dqrr.next_idx++; + s->dqrr.next_idx &= 3; /* Wrap around at 4 */ + /* TODO: it's possible to do all this without conditionals, optimise it + * later. */ + if (!s->dqrr.next_idx) + s->dqrr.valid_bit ^= QB_VALID_BIT; + /* VDQCR "no longer busy" hook - if VDQCR shows "busy" and this is a + * VDQCR result, mark it as non-busy. */ + if (s->vdq.busy) { + uint32_t flags = ldpaa_dq_flags(dq); + + response_verb = qb_attr_code_decode(&code_dqrr_response, &verb); + if ((response_verb == QBMAN_DQRR_RESPONSE_DQ) && + (flags & LDPAA_DQ_STAT_VOLATILE)) + s->vdq.busy = 0; + } + qbman_cena_invalidate_prefetch(&s->sys, + QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); + return dq; +} + +/* Consume DQRR entries previously returned from qbman_swp_dqrr_next(). */ +void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct ldpaa_dq *dq) +{ + qbman_cinh_write(&s->sys, QBMAN_CINH_SWP_DCAP, QBMAN_IDX_FROM_DQRR(dq)); +} + +/*********************************/ +/* Polling user-provided storage */ +/*********************************/ + +void qbman_dq_entry_set_oldtoken(struct ldpaa_dq *dq, + unsigned int num_entries, + uint8_t oldtoken) +{ + memset(dq, oldtoken, num_entries * sizeof(*dq)); +} + +int qbman_dq_entry_has_newtoken(struct qbman_swp *s, + const struct ldpaa_dq *dq, + uint8_t newtoken) +{ + /* To avoid converting the little-endian DQ entry to host-endian prior + * to us knowing whether there is a valid entry or not (and run the + * risk of corrupting the incoming hardware LE write), we detect in + * hardware endianness rather than host. This means we need a different + * "code" depending on whether we are BE or LE in software, which is + * where DQRR_TOK_OFFSET comes in... */ + static struct qb_attr_code code_dqrr_tok_detect = + QB_CODE(0, DQRR_TOK_OFFSET, 8); + /* The user trying to poll for a result treats "dq" as const. It is + * however the same address that was provided to us non-const in the + * first place, for directing hardware DMA to. So we can cast away the + * const because it is mutable from our perspective. */ + uint32_t *p = qb_cl((struct ldpaa_dq *)dq); + uint32_t token; + + token = qb_attr_code_decode(&code_dqrr_tok_detect, &p[1]); + if (token != newtoken) + return 0; + + /* Only now do we convert from hardware to host endianness. Also, as we + * are returning success, the user has promised not to call us again, so + * there's no risk of us converting the endianness twice... */ + make_le32_n(p, 16); + + /* VDQCR "no longer busy" hook - not quite the same as DQRR, because the + * fact "VDQCR" shows busy doesn't mean that the result we're looking at + * is from the same command. Eg. we may be looking at our 10th dequeue + * result from our first VDQCR command, yet the second dequeue command + * could have been kicked off already, after seeing the 1st result. Ie. + * the result we're looking at is not necessarily proof that we can + * reset "busy". We instead base the decision on whether the current + * result is sitting at the first 'storage' location of the busy + * command. */ + if (s->vdq.busy && (s->vdq.storage == dq)) + s->vdq.busy = 0; + return 1; +} + +/********************************/ +/* Categorising dequeue entries */ +/********************************/ + +static inline int __qbman_dq_entry_is_x(const struct ldpaa_dq *dq, uint32_t x) +{ + const uint32_t *p = qb_cl(dq); + uint32_t response_verb = qb_attr_code_decode(&code_dqrr_response, p); + + return response_verb == x; +} + +int qbman_dq_entry_is_DQ(const struct ldpaa_dq *dq) +{ + return __qbman_dq_entry_is_x(dq, QBMAN_DQRR_RESPONSE_DQ); +} + +/*********************************/ +/* Parsing frame dequeue results */ +/*********************************/ + +/* These APIs assume qbman_dq_entry_is_DQ() is TRUE */ + +uint32_t ldpaa_dq_flags(const struct ldpaa_dq *dq) +{ + const uint32_t *p = qb_cl(dq); + + return qb_attr_code_decode(&code_dqrr_stat, p); +} + +const struct dpaa_fd *ldpaa_dq_fd(const struct ldpaa_dq *dq) +{ + const uint32_t *p = qb_cl(dq); + + return (const struct dpaa_fd *)&p[8]; +} + +/******************/ +/* Buffer release */ +/******************/ + +/* These should be const, eventually */ +/* static struct qb_attr_code code_release_num = QB_CODE(0, 0, 3); */ +static struct qb_attr_code code_release_set_me = QB_CODE(0, 5, 1); +static struct qb_attr_code code_release_bpid = QB_CODE(0, 16, 16); + +void qbman_release_desc_clear(struct qbman_release_desc *d) +{ + uint32_t *cl; + + memset(d, 0, sizeof(*d)); + cl = qb_cl(d); + qb_attr_code_encode(&code_release_set_me, cl, 1); +} + +void qbman_release_desc_set_bpid(struct qbman_release_desc *d, uint32_t bpid) +{ + uint32_t *cl = qb_cl(d); + + qb_attr_code_encode(&code_release_bpid, cl, bpid); +} + +#define RAR_IDX(rar) ((rar) & 0x7) +#define RAR_VB(rar) ((rar) & 0x80) +#define RAR_SUCCESS(rar) ((rar) & 0x100) + +int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, + const uint64_t *buffers, unsigned int num_buffers) +{ + uint32_t *p; + const uint32_t *cl = qb_cl(d); + uint32_t rar = qbman_cinh_read(&s->sys, QBMAN_CINH_SWP_RAR); + debug("RAR=%08x\n", rar); + if (!RAR_SUCCESS(rar)) + return -EBUSY; + BUG_ON(!num_buffers || (num_buffers > 7)); + /* Start the release command */ + p = qbman_cena_write_start(&s->sys, + QBMAN_CENA_SWP_RCR(RAR_IDX(rar))); + /* Copy the caller's buffer pointers to the command */ + u64_to_le32_copy(&p[2], buffers, num_buffers); + lwsync(); + /* Set the verb byte, have to substitute in the valid-bit and the number + * of buffers. */ + p[0] = cl[0] | RAR_VB(rar) | num_buffers; + qbman_cena_write_complete(&s->sys, + QBMAN_CENA_SWP_RCR(RAR_IDX(rar)), + p); + return 0; +} + +/*******************/ +/* Buffer acquires */ +/*******************/ + +/* These should be const, eventually */ +static struct qb_attr_code code_acquire_bpid = QB_CODE(0, 16, 16); +static struct qb_attr_code code_acquire_num = QB_CODE(1, 0, 3); +static struct qb_attr_code code_acquire_r_num = QB_CODE(1, 0, 3); + +int qbman_swp_acquire(struct qbman_swp *s, uint32_t bpid, uint64_t *buffers, + unsigned int num_buffers) +{ + uint32_t *p; + uint32_t verb, rslt, num; + + BUG_ON(!num_buffers || (num_buffers > 7)); + + /* Start the management command */ + p = qbman_swp_mc_start(s); + + if (!p) + return -EBUSY; + + /* Encode the caller-provided attributes */ + qb_attr_code_encode(&code_acquire_bpid, p, bpid); + qb_attr_code_encode(&code_acquire_num, p, num_buffers); + + /* Complete the management command */ + p = qbman_swp_mc_complete(s, p, p[0] | QBMAN_MC_ACQUIRE); + + /* Decode the outcome */ + verb = qb_attr_code_decode(&code_generic_verb, p); + rslt = qb_attr_code_decode(&code_generic_rslt, p); + num = qb_attr_code_decode(&code_acquire_r_num, p); + BUG_ON(verb != QBMAN_MC_ACQUIRE); + + /* Determine success or failure */ + if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { + printf("Acquire buffers from BPID 0x%x failed, code=0x%02x\n", + bpid, rslt); + return -EIO; + } + BUG_ON(num > num_buffers); + /* Copy the acquired buffers to the caller's array */ + u64_from_le32_copy(buffers, &p[2], num); + return (int)num; +} diff --git a/drivers/net/fsl-mc/dpio/qbman_portal.h b/drivers/net/fsl-mc/dpio/qbman_portal.h new file mode 100644 index 0000000..bb67c3b --- /dev/null +++ b/drivers/net/fsl-mc/dpio/qbman_portal.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "qbman_private.h" +#include <fsl-mc/fsl_qbman_portal.h> +#include <fsl-mc/fsl_dpaa_fd.h> + +/* All QBMan command and result structures use this "valid bit" encoding */ +#define QB_VALID_BIT ((uint32_t)0x80) + +/* Management command result codes */ +#define QBMAN_MC_RSLT_OK 0xf0 + +/* --------------------- */ +/* portal data structure */ +/* --------------------- */ + +struct qbman_swp { + const struct qbman_swp_desc *desc; + /* The qbman_sys (ie. arch/OS-specific) support code can put anything it + * needs in here. */ + struct qbman_swp_sys sys; + /* Management commands */ + struct { +#ifdef QBMAN_CHECKING + enum swp_mc_check { + swp_mc_can_start, /* call __qbman_swp_mc_start() */ + swp_mc_can_submit, /* call __qbman_swp_mc_submit() */ + swp_mc_can_poll, /* call __qbman_swp_mc_result() */ + } check; +#endif + uint32_t valid_bit; /* 0x00 or 0x80 */ + } mc; + /* Push dequeues */ + uint32_t sdq; + /* Volatile dequeues */ + struct { + /* VDQCR supports a "1 deep pipeline", meaning that if you know + * the last-submitted command is already executing in the + * hardware (as evidenced by at least 1 valid dequeue result), + * you can write another dequeue command to the register, the + * hardware will start executing it as soon as the + * already-executing command terminates. (This minimises latency + * and stalls.) With that in mind, this "busy" variable refers + * to whether or not a command can be submitted, not whether or + * not a previously-submitted command is still executing. In + * other words, once proof is seen that the previously-submitted + * command is executing, "vdq" is no longer "busy". TODO: + * convert this to "atomic_t" so that it is thread-safe (without + * locking). */ + int busy; + uint32_t valid_bit; /* 0x00 or 0x80 */ + /* We need to determine when vdq is no longer busy. This depends + * on whether the "busy" (last-submitted) dequeue command is + * targetting DQRR or main-memory, and detected is based on the + * presence of the dequeue command's "token" showing up in + * dequeue entries in DQRR or main-memory (respectively). Debug + * builds will, when submitting vdq commands, verify that the + * dequeue result location is not already equal to the command's + * token value. */ + struct ldpaa_dq *storage; /* NULL if DQRR */ + uint32_t token; + } vdq; + /* DQRR */ + struct { + uint32_t next_idx; + uint32_t valid_bit; + } dqrr; +}; + +/* -------------------------- */ +/* portal management commands */ +/* -------------------------- */ + +/* Different management commands all use this common base layer of code to issue + * commands and poll for results. The first function returns a pointer to where + * the caller should fill in their MC command (though they should ignore the + * verb byte), the second function commits merges in the caller-supplied command + * verb (which should not include the valid-bit) and submits the command to + * hardware, and the third function checks for a completed response (returns + * non-NULL if only if the response is complete). */ +void *qbman_swp_mc_start(struct qbman_swp *p); +void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb); +void *qbman_swp_mc_result(struct qbman_swp *p); + +/* Wraps up submit + poll-for-result */ +static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd, + uint32_t cmd_verb) +{ + int loopvar; + + qbman_swp_mc_submit(swp, cmd, cmd_verb); + DBG_POLL_START(loopvar); + do { + DBG_POLL_CHECK(loopvar); + cmd = qbman_swp_mc_result(swp); + } while (!cmd); + return cmd; +} + +/* ------------ */ +/* qb_attr_code */ +/* ------------ */ + +/* This struct locates a sub-field within a QBMan portal (CENA) cacheline which + * is either serving as a configuration command or a query result. The + * representation is inherently little-endian, as the indexing of the words is + * itself little-endian in nature and layerscape is little endian for anything + * that crosses a word boundary too (64-bit fields are the obvious examples). + */ +struct qb_attr_code { + unsigned int word; /* which uint32_t[] array member encodes the field */ + unsigned int lsoffset; /* encoding offset from ls-bit */ + unsigned int width; /* encoding width. (bool must be 1.) */ +}; + +/* Macros to define codes */ +#define QB_CODE(a, b, c) { a, b, c} + +/* decode a field from a cacheline */ +static inline uint32_t qb_attr_code_decode(const struct qb_attr_code *code, + const uint32_t *cacheline) +{ + return d32_uint32_t(code->lsoffset, code->width, cacheline[code->word]); +} + +/* encode a field to a cacheline */ +static inline void qb_attr_code_encode(const struct qb_attr_code *code, + uint32_t *cacheline, uint32_t val) +{ + cacheline[code->word] = + r32_uint32_t(code->lsoffset, code->width, cacheline[code->word]) + | e32_uint32_t(code->lsoffset, code->width, val); +} + +/* ---------------------- */ +/* Descriptors/cachelines */ +/* ---------------------- */ + +/* To avoid needless dynamic allocation, the driver API often gives the caller + * a "descriptor" type that the caller can instantiate however they like. + * Ultimately though, it is just a cacheline of binary storage (or something + * smaller when it is known that the descriptor doesn't need all 64 bytes) for + * holding pre-formatted pieces of harware commands. The performance-critical + * code can then copy these descriptors directly into hardware command + * registers more efficiently than trying to construct/format commands + * on-the-fly. The API user sees the descriptor as an array of 32-bit words in + * order for the compiler to know its size, but the internal details are not + * exposed. The following macro is used within the driver for converting *any* + * descriptor pointer to a usable array pointer. The use of a macro (instead of + * an inline) is necessary to work with different descriptor types and to work + * correctly with const and non-const inputs (and similarly-qualified outputs). + */ +#define qb_cl(d) (&(d)->dont_manipulate_directly[0]) diff --git a/drivers/net/fsl-mc/dpio/qbman_private.h b/drivers/net/fsl-mc/dpio/qbman_private.h new file mode 100644 index 0000000..2d2556b --- /dev/null +++ b/drivers/net/fsl-mc/dpio/qbman_private.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Perform extra checking */ +#include <common.h> +#include <errno.h> +#include <asm/io.h> +#include <linux/types.h> +#include <linux/compat.h> +#include <malloc.h> +#include <fsl-mc/fsl_qbman_base.h> + +#define QBMAN_CHECKING + +/* Any time there is a register interface which we poll on, this provides a + * "break after x iterations" scheme for it. It's handy for debugging, eg. + * where you don't want millions of lines of log output from a polling loop + * that won't, because such things tend to drown out the earlier log output + * that might explain what caused the problem. (NB: put ";" after each macro!) + * TODO: we should probably remove this once we're done sanitising the + * simulator... + */ +#define DBG_POLL_START(loopvar) (loopvar = 10) +#define DBG_POLL_CHECK(loopvar) \ + do {if (!(loopvar--)) BUG_ON(NULL == "DBG_POLL_CHECK"); } while (0) + +/* For CCSR or portal-CINH registers that contain fields at arbitrary offsets + * and widths, these macro-generated encode/decode/isolate/remove inlines can + * be used. + * + * Eg. to "d"ecode a 14-bit field out of a register (into a "uint16_t" type), + * where the field is located 3 bits "up" from the least-significant bit of the + * register (ie. the field location within the 32-bit register corresponds to a + * mask of 0x0001fff8), you would do; + * uint16_t field = d32_uint16_t(3, 14, reg_value); + * + * Or to "e"ncode a 1-bit boolean value (input type is "int", zero is FALSE, + * non-zero is TRUE, so must convert all non-zero inputs to 1, hence the "!!" + * operator) into a register at bit location 0x00080000 (19 bits "in" from the + * LS bit), do; + * reg_value |= e32_int(19, 1, !!field); + * + * If you wish to read-modify-write a register, such that you leave the 14-bit + * field as-is but have all other fields set to zero, then "i"solate the 14-bit + * value using; + * reg_value = i32_uint16_t(3, 14, reg_value); + * + * Alternatively, you could "r"emove the 1-bit boolean field (setting it to + * zero) but leaving all other fields as-is; + * reg_val = r32_int(19, 1, reg_value); + * + */ +#define MAKE_MASK32(width) (width == 32 ? 0xffffffff : \ + (uint32_t)((1 << width) - 1)) +#define DECLARE_CODEC32(t) \ +static inline uint32_t e32_##t(uint32_t lsoffset, uint32_t width, t val) \ +{ \ + BUG_ON(width > (sizeof(t) * 8)); \ + return ((uint32_t)val & MAKE_MASK32(width)) << lsoffset; \ +} \ +static inline t d32_##t(uint32_t lsoffset, uint32_t width, uint32_t val) \ +{ \ + BUG_ON(width > (sizeof(t) * 8)); \ + return (t)((val >> lsoffset) & MAKE_MASK32(width)); \ +} \ +static inline uint32_t i32_##t(uint32_t lsoffset, uint32_t width, \ + uint32_t val) \ +{ \ + BUG_ON(width > (sizeof(t) * 8)); \ + return e32_##t(lsoffset, width, d32_##t(lsoffset, width, val)); \ +} \ +static inline uint32_t r32_##t(uint32_t lsoffset, uint32_t width, \ + uint32_t val) \ +{ \ + BUG_ON(width > (sizeof(t) * 8)); \ + return ~(MAKE_MASK32(width) << lsoffset) & val; \ +} +DECLARE_CODEC32(uint32_t) +DECLARE_CODEC32(uint16_t) +DECLARE_CODEC32(uint8_t) +DECLARE_CODEC32(int) + + /*********************/ + /* Debugging assists */ + /*********************/ + +static inline void __hexdump(unsigned long start, unsigned long end, + unsigned long p, size_t sz, const unsigned char *c) +{ + while (start < end) { + unsigned int pos = 0; + char buf[64]; + int nl = 0; + + pos += sprintf(buf + pos, "%08lx: ", start); + do { + if ((start < p) || (start >= (p + sz))) + pos += sprintf(buf + pos, ".."); + else + pos += sprintf(buf + pos, "%02x", *(c++)); + if (!(++start & 15)) { + buf[pos++] = '\n'; + nl = 1; + } else { + nl = 0; + if (!(start & 1)) + buf[pos++] = ' '; + if (!(start & 3)) + buf[pos++] = ' '; + } + } while (start & 15); + if (!nl) + buf[pos++] = '\n'; + buf[pos] = '\0'; + debug("%s", buf); + } +} +static inline void hexdump(const void *ptr, size_t sz) +{ + unsigned long p = (unsigned long)ptr; + unsigned long start = p & ~(unsigned long)15; + unsigned long end = (p + sz + 15) & ~(unsigned long)15; + const unsigned char *c = ptr; + + __hexdump(start, end, p, sz, c); +} + +#if defined(__BIG_ENDIAN) +#define DQRR_TOK_OFFSET 0 +#else +#define DQRR_TOK_OFFSET 24 +#endif + +/* Similarly-named functions */ +#define upper32(a) upper_32_bits(a) +#define lower32(a) lower_32_bits(a) + + /****************/ + /* arch assists */ + /****************/ + +static inline void dcbz(void *ptr) +{ + uint32_t *p = ptr; + BUG_ON((unsigned long)ptr & 63); + p[0] = 0; + p[1] = 0; + p[2] = 0; + p[3] = 0; + p[4] = 0; + p[5] = 0; + p[6] = 0; + p[7] = 0; + p[8] = 0; + p[9] = 0; + p[10] = 0; + p[11] = 0; + p[12] = 0; + p[13] = 0; + p[14] = 0; + p[15] = 0; +} + +#define lwsync() + +#include "qbman_sys.h" diff --git a/drivers/net/fsl-mc/dpio/qbman_sys.h b/drivers/net/fsl-mc/dpio/qbman_sys.h new file mode 100644 index 0000000..235d641 --- /dev/null +++ b/drivers/net/fsl-mc/dpio/qbman_sys.h @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* qbman_sys_decl.h and qbman_sys.h are the two platform-specific files in the + * driver. They are only included via qbman_private.h, which is itself a + * platform-independent file and is included by all the other driver source. + * + * qbman_sys_decl.h is included prior to all other declarations and logic, and + * it exists to provide compatibility with any linux interfaces our + * single-source driver code is dependent on (eg. kmalloc). Ie. this file + * provides linux compatibility. + * + * This qbman_sys.h header, on the other hand, is included *after* any common + * and platform-neutral declarations and logic in qbman_private.h, and exists to + * implement any platform-specific logic of the qbman driver itself. Ie. it is + * *not* to provide linux compatibility. + */ + +/* Trace the 3 different classes of read/write access to QBMan. #undef as + * required. */ +#undef QBMAN_CCSR_TRACE +#undef QBMAN_CINH_TRACE +#undef QBMAN_CENA_TRACE + +/* Temporarily define this to get around the fact that cache enabled mapping is + * not working right now. Will remove this after uboot could map the cache + * enabled portal memory. + */ +#define QBMAN_CINH_ONLY + +static inline void word_copy(void *d, const void *s, unsigned int cnt) +{ + uint32_t *dd = d; + const uint32_t *ss = s; + + while (cnt--) + *(dd++) = *(ss++); +} + +/* Currently, the CENA support code expects each 32-bit word to be written in + * host order, and these are converted to hardware (little-endian) order on + * command submission. However, 64-bit quantities are must be written (and read) + * as two 32-bit words with the least-significant word first, irrespective of + * host endianness. */ +static inline void u64_to_le32_copy(void *d, const uint64_t *s, + unsigned int cnt) +{ + uint32_t *dd = d; + const uint32_t *ss = (const uint32_t *)s; + + while (cnt--) { + /* TBD: the toolchain was choking on the use of 64-bit types up + * until recently so this works entirely with 32-bit variables. + * When 64-bit types become usable again, investigate better + * ways of doing this. */ +#if defined(__BIG_ENDIAN) + *(dd++) = ss[1]; + *(dd++) = ss[0]; + ss += 2; +#else + *(dd++) = *(ss++); + *(dd++) = *(ss++); +#endif + } +} +static inline void u64_from_le32_copy(uint64_t *d, const void *s, + unsigned int cnt) +{ + const uint32_t *ss = s; + uint32_t *dd = (uint32_t *)d; + + while (cnt--) { +#if defined(__BIG_ENDIAN) + dd[1] = *(ss++); + dd[0] = *(ss++); + dd += 2; +#else + *(dd++) = *(ss++); + *(dd++) = *(ss++); +#endif + } +} + +/* Convert a host-native 32bit value into little endian */ +#if defined(__BIG_ENDIAN) +static inline uint32_t make_le32(uint32_t val) +{ + return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | + ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24); +} +#else +#define make_le32(val) (val) +#endif +static inline void make_le32_n(uint32_t *val, unsigned int num) +{ + while (num--) { + *val = make_le32(*val); + val++; + } +} + + /******************/ + /* Portal access */ + /******************/ +struct qbman_swp_sys { + /* On GPP, the sys support for qbman_swp is here. The CENA region isi + * not an mmap() of the real portal registers, but an allocated + * place-holder, because the actual writes/reads to/from the portal are + * marshalled from these allocated areas using QBMan's "MC access + * registers". CINH accesses are atomic so there's no need for a + * place-holder. */ + void *cena; + void __iomem *addr_cena; + void __iomem *addr_cinh; +}; + +/* P_OFFSET is (ACCESS_CMD,0,12) - offset within the portal + * C is (ACCESS_CMD,12,1) - is inhibited? (0==CENA, 1==CINH) + * SWP_IDX is (ACCESS_CMD,16,10) - Software portal index + * P is (ACCESS_CMD,28,1) - (0==special portal, 1==any portal) + * T is (ACCESS_CMD,29,1) - Command type (0==READ, 1==WRITE) + * E is (ACCESS_CMD,31,1) - Command execute (1 to issue, poll for 0==complete) + */ + +static inline void qbman_cinh_write(struct qbman_swp_sys *s, uint32_t offset, + uint32_t val) +{ + __raw_writel(val, s->addr_cinh + offset); +#ifdef QBMAN_CINH_TRACE + pr_info("qbman_cinh_write(%p:0x%03x) 0x%08x\n", + s->addr_cinh, offset, val); +#endif +} + +static inline uint32_t qbman_cinh_read(struct qbman_swp_sys *s, uint32_t offset) +{ + uint32_t reg = __raw_readl(s->addr_cinh + offset); + +#ifdef QBMAN_CINH_TRACE + pr_info("qbman_cinh_read(%p:0x%03x) 0x%08x\n", + s->addr_cinh, offset, reg); +#endif + return reg; +} + +static inline void *qbman_cena_write_start(struct qbman_swp_sys *s, + uint32_t offset) +{ + void *shadow = s->cena + offset; + +#ifdef QBMAN_CENA_TRACE + pr_info("qbman_cena_write_start(%p:0x%03x) %p\n", + s->addr_cena, offset, shadow); +#endif + BUG_ON(offset & 63); + dcbz(shadow); + return shadow; +} + +static inline void qbman_cena_write_complete(struct qbman_swp_sys *s, + uint32_t offset, void *cmd) +{ + const uint32_t *shadow = cmd; + int loop; + +#ifdef QBMAN_CENA_TRACE + pr_info("qbman_cena_write_complete(%p:0x%03x) %p\n", + s->addr_cena, offset, shadow); + hexdump(cmd, 64); +#endif + for (loop = 15; loop >= 0; loop--) +#ifdef QBMAN_CINH_ONLY + __raw_writel(shadow[loop], s->addr_cinh + + offset + loop * 4); +#else + __raw_writel(shadow[loop], s->addr_cena + + offset + loop * 4); +#endif +} + +static inline void *qbman_cena_read(struct qbman_swp_sys *s, uint32_t offset) +{ + uint32_t *shadow = s->cena + offset; + unsigned int loop; + +#ifdef QBMAN_CENA_TRACE + pr_info("qbman_cena_read(%p:0x%03x) %p\n", + s->addr_cena, offset, shadow); +#endif + + for (loop = 0; loop < 16; loop++) +#ifdef QBMAN_CINH_ONLY + shadow[loop] = __raw_readl(s->addr_cinh + offset + + loop * 4); +#else + shadow[loop] = __raw_readl(s->addr_cena + offset + + loop * 4); +#endif +#ifdef QBMAN_CENA_TRACE + hexdump(shadow, 64); +#endif + return shadow; +} + +static inline void qbman_cena_invalidate_prefetch(struct qbman_swp_sys *s, + uint32_t offset) +{ +} + + /******************/ + /* Portal support */ + /******************/ + +/* The SWP_CFG portal register is special, in that it is used by the + * platform-specific code rather than the platform-independent code in + * qbman_portal.c. So use of it is declared locally here. */ +#define QBMAN_CINH_SWP_CFG 0xd00 + +/* For MC portal use, we always configure with + * DQRR_MF is (SWP_CFG,20,3) - DQRR max fill (<- 0x4) + * EST is (SWP_CFG,16,3) - EQCR_CI stashing threshold (<- 0x0) + * RPM is (SWP_CFG,12,2) - RCR production notification mode (<- 0x3) + * DCM is (SWP_CFG,10,2) - DQRR consumption notification mode (<- 0x2) + * EPM is (SWP_CFG,8,2) - EQCR production notification mode (<- 0x3) + * SD is (SWP_CFG,5,1) - memory stashing drop enable (<- FALSE) + * SP is (SWP_CFG,4,1) - memory stashing priority (<- TRUE) + * SE is (SWP_CFG,3,1) - memory stashing enable (<- 0x0) + * DP is (SWP_CFG,2,1) - dequeue stashing priority (<- TRUE) + * DE is (SWP_CFG,1,1) - dequeue stashing enable (<- 0x0) + * EP is (SWP_CFG,0,1) - EQCR_CI stashing priority (<- FALSE) + */ +static inline uint32_t qbman_set_swp_cfg(uint8_t max_fill, uint8_t wn, + uint8_t est, uint8_t rpm, uint8_t dcm, + uint8_t epm, int sd, int sp, int se, + int dp, int de, int ep) +{ + uint32_t reg; + + reg = e32_uint8_t(20, 3, max_fill) | e32_uint8_t(16, 3, est) | + e32_uint8_t(12, 2, rpm) | e32_uint8_t(10, 2, dcm) | + e32_uint8_t(8, 2, epm) | e32_int(5, 1, sd) | + e32_int(4, 1, sp) | e32_int(3, 1, se) | e32_int(2, 1, dp) | + e32_int(1, 1, de) | e32_int(0, 1, ep) | e32_uint8_t(14, 1, wn); + return reg; +} + +static inline int qbman_swp_sys_init(struct qbman_swp_sys *s, + const struct qbman_swp_desc *d) +{ + uint32_t reg; + + s->addr_cena = d->cena_bar; + s->addr_cinh = d->cinh_bar; + s->cena = (void *)valloc(CONFIG_SYS_PAGE_SIZE); + memset((void *)s->cena, 0x00, CONFIG_SYS_PAGE_SIZE); + if (!s->cena) { + printf("Could not allocate page for cena shadow\n"); + return -1; + } + +#ifdef QBMAN_CHECKING + /* We should never be asked to initialise for a portal that isn't in + * the power-on state. (Ie. don't forget to reset portals when they are + * decommissioned!) + */ + reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG); + BUG_ON(reg); +#endif +#ifdef QBMAN_CINH_ONLY + reg = qbman_set_swp_cfg(4, 1, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0); +#else + reg = qbman_set_swp_cfg(4, 0, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0); +#endif + qbman_cinh_write(s, QBMAN_CINH_SWP_CFG, reg); + reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG); + if (!reg) { + printf("The portal is not enabled!\n"); + free(s->cena); + return -1; + } + return 0; +} + +static inline void qbman_swp_sys_finish(struct qbman_swp_sys *s) +{ + free((void *)s->cena); +} diff --git a/drivers/net/fsl-mc/dpmng.c b/drivers/net/fsl-mc/dpmng.c index cc14c7b..01ee112 100644 --- a/drivers/net/fsl-mc/dpmng.c +++ b/drivers/net/fsl-mc/dpmng.c @@ -1,4 +1,4 @@ -/* Copyright 2014 Freescale Semiconductor Inc. +/* Copyright 2013-2015 Freescale Semiconductor Inc. * * SPDX-License-Identifier: GPL-2.0+ */ @@ -26,66 +26,3 @@ int mc_get_version(struct fsl_mc_io *mc_io, struct mc_version *mc_ver_info) return 0; } - -int dpmng_reset_aiop(struct fsl_mc_io *mc_io, int container_id, - int aiop_tile_id) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMNG_CMDID_RESET_AIOP, - MC_CMD_PRI_LOW, 0); - DPMNG_CMD_RESET_AIOP(cmd, container_id, aiop_tile_id); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpmng_load_aiop(struct fsl_mc_io *mc_io, - int container_id, - int aiop_tile_id, - uint64_t img_iova, - uint32_t img_size) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMNG_CMDID_LOAD_AIOP, - MC_CMD_PRI_LOW, - 0); - DPMNG_CMD_LOAD_AIOP(cmd, container_id, aiop_tile_id, img_size, - img_iova); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpmng_run_aiop(struct fsl_mc_io *mc_io, - int container_id, - int aiop_tile_id, - const struct dpmng_aiop_run_cfg *cfg) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMNG_CMDID_RUN_AIOP, - MC_CMD_PRI_LOW, - 0); - DPMNG_CMD_RUN_AIOP(cmd, container_id, aiop_tile_id, cfg); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -int dpmng_reset_mc_portal(struct fsl_mc_io *mc_io) -{ - struct mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPMNG_CMDID_RESET_MC_PORTAL, - MC_CMD_PRI_LOW, - 0); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} diff --git a/drivers/net/fsl-mc/dpni.c b/drivers/net/fsl-mc/dpni.c new file mode 100644 index 0000000..b384401 --- /dev/null +++ b/drivers/net/fsl-mc/dpni.c @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2013-2015 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <fsl-mc/fsl_mc_sys.h> +#include <fsl-mc/fsl_mc_cmd.h> +#include <fsl-mc/fsl_dpni.h> + +int dpni_open(struct fsl_mc_io *mc_io, int dpni_id, uint16_t *token) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_OPEN, + MC_CMD_PRI_LOW, 0); + DPNI_CMD_OPEN(cmd, dpni_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + + return 0; +} + +int dpni_close(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE, + MC_CMD_PRI_HIGH, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_pools(struct fsl_mc_io *mc_io, + uint16_t token, + const struct dpni_pools_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_POOLS, + MC_CMD_PRI_LOW, + token); + DPNI_CMD_SET_POOLS(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_enable(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_disable(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE, + MC_CMD_PRI_LOW, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_reset(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_attributes(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpni_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR, + MC_CMD_PRI_LOW, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_ATTR(cmd, attr); + + return 0; +} + +int dpni_get_rx_buffer_layout(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_BUFFER_LAYOUT, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_RX_BUFFER_LAYOUT(cmd, layout); + + return 0; +} + +int dpni_set_rx_buffer_layout(struct fsl_mc_io *mc_io, + uint16_t token, + const struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_BUFFER_LAYOUT, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_RX_BUFFER_LAYOUT(cmd, layout); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_buffer_layout(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_BUFFER_LAYOUT, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_BUFFER_LAYOUT(cmd, layout); + + return 0; +} + +int dpni_set_tx_buffer_layout(struct fsl_mc_io *mc_io, + uint16_t token, + const struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_BUFFER_LAYOUT, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_TX_BUFFER_LAYOUT(cmd, layout); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_conf_buffer_layout(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_CONF_BUFFER_LAYOUT, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_CONF_BUFFER_LAYOUT(cmd, layout); + + return 0; +} + +int dpni_set_tx_conf_buffer_layout(struct fsl_mc_io *mc_io, + uint16_t token, + const struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONF_BUFFER_LAYOUT, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_TX_CONF_BUFFER_LAYOUT(cmd, layout); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_qdid(struct fsl_mc_io *mc_io, uint16_t token, uint16_t *qdid) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QDID, + MC_CMD_PRI_LOW, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_QDID(cmd, *qdid); + + return 0; +} + +int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, + uint16_t token, + uint16_t *data_offset) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_DATA_OFFSET, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_DATA_OFFSET(cmd, *data_offset); + + return 0; +} + +int dpni_get_counter(struct fsl_mc_io *mc_io, + uint16_t token, + enum dpni_counter counter, + uint64_t *value) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_COUNTER, + MC_CMD_PRI_LOW, token); + DPNI_CMD_GET_COUNTER(cmd, counter); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_COUNTER(cmd, *value); + + return 0; +} + +int dpni_set_counter(struct fsl_mc_io *mc_io, + uint16_t token, + enum dpni_counter counter, + uint64_t value) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_COUNTER, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_COUNTER(cmd, counter, value); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_link_cfg(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpni_link_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_LINK_CFG(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_link_state(struct fsl_mc_io *mc_io, + uint16_t token, + struct dpni_link_state *state) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_LINK_STATE(cmd, state); + + return 0; +} + + +int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_PRIM_MAC, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_PRIMARY_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, + uint16_t token, + uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PRIM_MAC, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_PRIMARY_MAC_ADDR(cmd, mac_addr); + + return 0; +} + +int dpni_add_mac_addr(struct fsl_mc_io *mc_io, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_MAC_ADDR, + MC_CMD_PRI_LOW, token); + DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_MAC_ADDR, + MC_CMD_PRI_LOW, token); + DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_tx_flow(struct fsl_mc_io *mc_io, + uint16_t token, + uint16_t *flow_id, + const struct dpni_tx_flow_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_FLOW, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_TX_FLOW(cmd, *flow_id, cfg); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_SET_TX_FLOW(cmd, *flow_id); + + return 0; +} + +int dpni_get_tx_flow(struct fsl_mc_io *mc_io, + uint16_t token, + uint16_t flow_id, + struct dpni_tx_flow_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_FLOW, + MC_CMD_PRI_LOW, token); + DPNI_CMD_GET_TX_FLOW(cmd, flow_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_FLOW(cmd, attr); + + return 0; +} + +int dpni_set_rx_flow(struct fsl_mc_io *mc_io, + uint16_t token, + uint8_t tc_id, + uint16_t flow_id, + const struct dpni_queue_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_FLOW, + MC_CMD_PRI_LOW, token); + DPNI_CMD_SET_RX_FLOW(cmd, tc_id, flow_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_rx_flow(struct fsl_mc_io *mc_io, + uint16_t token, + uint8_t tc_id, + uint16_t flow_id, + struct dpni_queue_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_FLOW, + MC_CMD_PRI_LOW, token); + DPNI_CMD_GET_RX_FLOW(cmd, tc_id, flow_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_RX_FLOW(cmd, attr); + + return 0; +} diff --git a/drivers/net/fsl-mc/dprc.c b/drivers/net/fsl-mc/dprc.c new file mode 100644 index 0000000..d481200 --- /dev/null +++ b/drivers/net/fsl-mc/dprc.c @@ -0,0 +1,283 @@ +/* + * Freescale Layerscape MC I/O wrapper + * + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. + * Author: German Rivera <German.Rivera@freescale.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <fsl-mc/fsl_mc_sys.h> +#include <fsl-mc/fsl_mc_cmd.h> +#include <fsl-mc/fsl_dprc.h> + +int dprc_get_container_id(struct fsl_mc_io *mc_io, int *container_id) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONT_ID, + MC_CMD_PRI_LOW, 0); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_CONTAINER_ID(cmd, *container_id); + + return 0; +} + +int dprc_open(struct fsl_mc_io *mc_io, int container_id, uint16_t *token) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_OPEN, MC_CMD_PRI_LOW, + 0); + DPRC_CMD_OPEN(cmd, container_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + + return 0; +} + +int dprc_close(struct fsl_mc_io *mc_io, uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLOSE, MC_CMD_PRI_HIGH, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dprc_reset_container(struct fsl_mc_io *mc_io, + uint16_t token, + int child_container_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT, + MC_CMD_PRI_LOW, token); + DPRC_CMD_RESET_CONTAINER(cmd, child_container_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dprc_get_attributes(struct fsl_mc_io *mc_io, + uint16_t token, + struct dprc_attributes *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_ATTR, + MC_CMD_PRI_LOW, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_ATTRIBUTES(cmd, attr); + + return 0; +} + +int dprc_get_obj_count(struct fsl_mc_io *mc_io, uint16_t token, int *obj_count) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_COUNT, + MC_CMD_PRI_LOW, token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_OBJ_COUNT(cmd, *obj_count); + + return 0; +} + +int dprc_get_obj(struct fsl_mc_io *mc_io, + uint16_t token, + int obj_index, + struct dprc_obj_desc *obj_desc) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ, + MC_CMD_PRI_LOW, + token); + DPRC_CMD_GET_OBJ(cmd, obj_index); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_OBJ(cmd, obj_desc); + + return 0; +} + +int dprc_get_res_count(struct fsl_mc_io *mc_io, + uint16_t token, + char *type, + int *res_count) +{ + struct mc_command cmd = { 0 }; + int err; + + *res_count = 0; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_COUNT, + MC_CMD_PRI_LOW, token); + DPRC_CMD_GET_RES_COUNT(cmd, type); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_RES_COUNT(cmd, *res_count); + + return 0; +} + +int dprc_get_res_ids(struct fsl_mc_io *mc_io, + uint16_t token, + char *type, + struct dprc_res_ids_range_desc *range_desc) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_IDS, + MC_CMD_PRI_LOW, token); + DPRC_CMD_GET_RES_IDS(cmd, range_desc, type); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_RES_IDS(cmd, range_desc); + + return 0; +} + +int dprc_get_obj_region(struct fsl_mc_io *mc_io, + uint16_t token, + char *obj_type, + int obj_id, + uint8_t region_index, + struct dprc_region_desc *region_desc) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, + MC_CMD_PRI_LOW, token); + DPRC_CMD_GET_OBJ_REGION(cmd, obj_type, obj_id, region_index); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_OBJ_REGION(cmd, region_desc); + + return 0; +} + +int dprc_connect(struct fsl_mc_io *mc_io, + uint16_t token, + const struct dprc_endpoint *endpoint1, + const struct dprc_endpoint *endpoint2) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_CONNECT, + MC_CMD_PRI_LOW, + token); + DPRC_CMD_CONNECT(cmd, endpoint1, endpoint2); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dprc_disconnect(struct fsl_mc_io *mc_io, + uint16_t token, + const struct dprc_endpoint *endpoint) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_DISCONNECT, + MC_CMD_PRI_LOW, + token); + DPRC_CMD_DISCONNECT(cmd, endpoint); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dprc_get_connection(struct fsl_mc_io *mc_io, + uint16_t token, + const struct dprc_endpoint *endpoint1, + struct dprc_endpoint *endpoint2, + int *state) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION, + MC_CMD_PRI_LOW, + token); + DPRC_CMD_GET_CONNECTION(cmd, endpoint1); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPRC_RSP_GET_CONNECTION(cmd, endpoint2, *state); + + return 0; +} diff --git a/drivers/net/fsl-mc/fsl_dpmng_cmd.h b/drivers/net/fsl-mc/fsl_dpmng_cmd.h index c9fe021..33f84f3 100644 --- a/drivers/net/fsl-mc/fsl_dpmng_cmd.h +++ b/drivers/net/fsl-mc/fsl_dpmng_cmd.h @@ -1,4 +1,4 @@ -/* Copyright 2014 Freescale Semiconductor Inc. +/* Copyright 2013-2015 Freescale Semiconductor Inc. * * SPDX-License-Identifier: GPL-2.0+ */ @@ -7,10 +7,6 @@ /* Command IDs */ #define DPMNG_CMDID_GET_VERSION 0x831 -#define DPMNG_CMDID_RESET_AIOP 0x832 -#define DPMNG_CMDID_LOAD_AIOP 0x833 -#define DPMNG_CMDID_RUN_AIOP 0x834 -#define DPMNG_CMDID_RESET_MC_PORTAL 0x835 /* cmd, param, offset, width, type, arg_name */ #define DPMNG_RSP_GET_VERSION(cmd, mc_ver_info) \ @@ -20,30 +16,4 @@ do { \ MC_RSP_OP(cmd, 1, 0, 32, uint32_t, mc_ver_info->minor); \ } while (0) -/* cmd, param, offset, width, type, arg_name */ -#define DPMNG_CMD_RESET_AIOP(cmd, container_id, aiop_tile_id) \ -do { \ - MC_CMD_OP(cmd, 0, 0, 32, int, aiop_tile_id); \ - MC_CMD_OP(cmd, 0, 32, 32, int, container_id); \ -} while (0) - -/* cmd, param, offset, width, type, arg_name */ -#define DPMNG_CMD_LOAD_AIOP(cmd, container_id, aiop_tile_id, img_size, \ - img_iova) \ -do { \ - MC_CMD_OP(cmd, 0, 0, 32, int, aiop_tile_id); \ - MC_CMD_OP(cmd, 0, 32, 32, int, container_id); \ - MC_CMD_OP(cmd, 1, 0, 32, uint32_t, img_size); \ - MC_CMD_OP(cmd, 2, 0, 64, uint64_t, img_iova); \ -} while (0) - -/* cmd, param, offset, width, type, arg_name */ -#define DPMNG_CMD_RUN_AIOP(cmd, container_id, aiop_tile_id, cfg) \ -do { \ - MC_CMD_OP(cmd, 0, 0, 32, int, aiop_tile_id); \ - MC_CMD_OP(cmd, 0, 32, 32, int, container_id); \ - MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->cores_mask); \ - MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->options); \ -} while (0) - #endif /* __FSL_DPMNG_CMD_H */ diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index 74b0085..c5c44bc 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -3,16 +3,75 @@ * * SPDX-License-Identifier: GPL-2.0+ */ - #include <errno.h> #include <asm/io.h> #include <fsl-mc/fsl_mc.h> #include <fsl-mc/fsl_mc_sys.h> +#include <fsl-mc/fsl_mc_private.h> #include <fsl-mc/fsl_dpmng.h> +#include <fsl_debug_server.h> +#include <fsl-mc/fsl_dprc.h> +#include <fsl-mc/fsl_dpio.h> +#include <fsl-mc/fsl_qbman_portal.h> + +#define MC_RAM_BASE_ADDR_ALIGNMENT (512UL * 1024 * 1024) +#define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1)) +#define MC_RAM_SIZE_ALIGNMENT (256UL * 1024 * 1024) + +#define MC_MEM_SIZE_ENV_VAR "mcmemsize" +#define MC_BOOT_TIMEOUT_ENV_VAR "mcboottimeout" DECLARE_GLOBAL_DATA_PTR; static int mc_boot_status; +struct fsl_mc_io *dflt_mc_io = NULL; +uint16_t dflt_dprc_handle = 0; +struct fsl_dpbp_obj *dflt_dpbp = NULL; +struct fsl_dpio_obj *dflt_dpio = NULL; +uint16_t dflt_dpio_handle = 0; + +#ifdef DEBUG +void dump_ram_words(const char *title, void *addr) +{ + int i; + uint32_t *words = addr; + + printf("Dumping beginning of %s (%p):\n", title, addr); + for (i = 0; i < 16; i++) + printf("%#x ", words[i]); + printf("\n"); +} + +void dump_mc_ccsr_regs(struct mc_ccsr_registers __iomem *mc_ccsr_regs) +{ + printf("MC CCSR registers:\n" + "reg_gcr1 %#x\n" + "reg_gsr %#x\n" + "reg_sicbalr %#x\n" + "reg_sicbahr %#x\n" + "reg_sicapr %#x\n" + "reg_mcfbalr %#x\n" + "reg_mcfbahr %#x\n" + "reg_mcfapr %#x\n" + "reg_psr %#x\n", + mc_ccsr_regs->reg_gcr1, + mc_ccsr_regs->reg_gsr, + mc_ccsr_regs->reg_sicbalr, + mc_ccsr_regs->reg_sicbahr, + mc_ccsr_regs->reg_sicapr, + mc_ccsr_regs->reg_mcfbalr, + mc_ccsr_regs->reg_mcfbahr, + mc_ccsr_regs->reg_mcfapr, + mc_ccsr_regs->reg_psr); +} +#else + +#define dump_ram_words(title, addr) +#define dump_mc_ccsr_regs(mc_ccsr_regs) + +#endif /* DEBUG */ + +#ifndef CONFIG_SYS_LS_MC_FW_IN_DDR /** * Copying MC firmware or DPL image to DDR */ @@ -21,6 +80,7 @@ static int mc_copy_image(const char *title, { debug("%s copied to address %p\n", title, (void *)mc_ram_addr); memcpy((void *)mc_ram_addr, (void *)image_addr, image_size); + flush_dcache_range(mc_ram_addr, mc_ram_addr + image_size); return 0; } @@ -82,23 +142,254 @@ int parse_mc_firmware_fit_image(const void **raw_image_addr, return 0; } +#endif + +/* + * Calculates the values to be used to specify the address range + * for the MC private DRAM block, in the MCFBALR/MCFBAHR registers. + * It returns the highest 512MB-aligned address within the given + * address range, in '*aligned_base_addr', and the number of 256 MiB + * blocks in it, in 'num_256mb_blocks'. + */ +static int calculate_mc_private_ram_params(u64 mc_private_ram_start_addr, + size_t mc_ram_size, + u64 *aligned_base_addr, + u8 *num_256mb_blocks) +{ + u64 addr; + u16 num_blocks; + + if (mc_ram_size % MC_RAM_SIZE_ALIGNMENT != 0) { + printf("fsl-mc: ERROR: invalid MC private RAM size (%lu)\n", + mc_ram_size); + return -EINVAL; + } + + num_blocks = mc_ram_size / MC_RAM_SIZE_ALIGNMENT; + if (num_blocks < 1 || num_blocks > 0xff) { + printf("fsl-mc: ERROR: invalid MC private RAM size (%lu)\n", + mc_ram_size); + return -EINVAL; + } + + addr = (mc_private_ram_start_addr + mc_ram_size - 1) & + MC_RAM_BASE_ADDR_ALIGNMENT_MASK; + + if (addr < mc_private_ram_start_addr) { + printf("fsl-mc: ERROR: bad start address %#llx\n", + mc_private_ram_start_addr); + return -EFAULT; + } + + *aligned_base_addr = addr; + *num_256mb_blocks = num_blocks; + return 0; +} + +static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size) +{ + u64 mc_dpc_offset; +#ifndef CONFIG_SYS_LS_MC_DPC_IN_DDR + int error; + void *dpc_fdt_hdr; + int dpc_size; +#endif + +#ifdef CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET + BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET & 0x3) != 0 || + CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET > 0xffffffff); + + mc_dpc_offset = CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET; +#else +#error "CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET not defined" +#endif + + /* + * Load the MC DPC blob in the MC private DRAM block: + */ +#ifdef CONFIG_SYS_LS_MC_DPC_IN_DDR + printf("MC DPC is preloaded to %#llx\n", mc_ram_addr + mc_dpc_offset); +#else + /* + * Get address and size of the DPC blob stored in flash: + */ +#ifdef CONFIG_SYS_LS_MC_DPC_IN_NOR + dpc_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPC_ADDR; +#else +#error "No CONFIG_SYS_LS_MC_DPC_IN_xxx defined" +#endif + + error = fdt_check_header(dpc_fdt_hdr); + if (error != 0) { + /* + * Don't return with error here, since the MC firmware can + * still boot without a DPC + */ + printf("fsl-mc: WARNING: No DPC image found\n"); + return 0; + } + + dpc_size = fdt_totalsize(dpc_fdt_hdr); + if (dpc_size > CONFIG_SYS_LS_MC_DPC_MAX_LENGTH) { + printf("fsl-mc: ERROR: Bad DPC image (too large: %d)\n", + dpc_size); + return -EINVAL; + } + + mc_copy_image("MC DPC blob", + (u64)dpc_fdt_hdr, dpc_size, mc_ram_addr + mc_dpc_offset); +#endif /* not defined CONFIG_SYS_LS_MC_DPC_IN_DDR */ + + dump_ram_words("DPC", (void *)(mc_ram_addr + mc_dpc_offset)); + return 0; +} -int mc_init(bd_t *bis) +static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size) +{ + u64 mc_dpl_offset; +#ifndef CONFIG_SYS_LS_MC_DPL_IN_DDR + int error; + void *dpl_fdt_hdr; + int dpl_size; +#endif + +#ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET + BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 || + CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff); + + mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET; +#else +#error "CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET not defined" +#endif + + /* + * Load the MC DPL blob in the MC private DRAM block: + */ +#ifdef CONFIG_SYS_LS_MC_DPL_IN_DDR + printf("MC DPL is preloaded to %#llx\n", mc_ram_addr + mc_dpl_offset); +#else + /* + * Get address and size of the DPL blob stored in flash: + */ +#ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR + dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR; +#else +#error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined" +#endif + + error = fdt_check_header(dpl_fdt_hdr); + if (error != 0) { + printf("fsl-mc: ERROR: Bad DPL image (bad header)\n"); + return error; + } + + dpl_size = fdt_totalsize(dpl_fdt_hdr); + if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) { + printf("fsl-mc: ERROR: Bad DPL image (too large: %d)\n", + dpl_size); + return -EINVAL; + } + + mc_copy_image("MC DPL blob", + (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset); +#endif /* not defined CONFIG_SYS_LS_MC_DPL_IN_DDR */ + + dump_ram_words("DPL", (void *)(mc_ram_addr + mc_dpl_offset)); + return 0; +} + +/** + * Return the MC boot timeout value in milliseconds + */ +static unsigned long get_mc_boot_timeout_ms(void) +{ + unsigned long timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS; + + char *timeout_ms_env_var = getenv(MC_BOOT_TIMEOUT_ENV_VAR); + + if (timeout_ms_env_var) { + timeout_ms = simple_strtoul(timeout_ms_env_var, NULL, 10); + if (timeout_ms == 0) { + printf("fsl-mc: WARNING: Invalid value for \'" + MC_BOOT_TIMEOUT_ENV_VAR + "\' environment variable: %lu\n", + timeout_ms); + + timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS; + } + } + + return timeout_ms; +} + +static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr) +{ + u32 reg_gsr; + u32 mc_fw_boot_status; + unsigned long timeout_ms = get_mc_boot_timeout_ms(); + struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; + + dmb(); + debug("Polling mc_ccsr_regs->reg_gsr ...\n"); + assert(timeout_ms > 0); + for (;;) { + udelay(1000); /* throttle polling */ + reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr); + mc_fw_boot_status = (reg_gsr & GSR_FS_MASK); + if (mc_fw_boot_status & 0x1) + break; + + timeout_ms--; + if (timeout_ms == 0) + break; + } + + if (timeout_ms == 0) { + if (booting_mc) + printf("fsl-mc: timeout booting management complex firmware\n"); + else + printf("fsl-mc: timeout deploying data path layout\n"); + + /* TODO: Get an error status from an MC CCSR register */ + return -ETIMEDOUT; + } + + if (mc_fw_boot_status != 0x1) { + /* + * TODO: Identify critical errors from the GSR register's FS + * field and for those errors, set error to -ENODEV or other + * appropriate errno, so that the status property is set to + * failure in the fsl,dprc device tree node. + */ + if (booting_mc) { + printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n", + reg_gsr); + } else { + printf("fsl-mc: WARNING: Data path layout deployed with error (GSR: %#x)\n", + reg_gsr); + } + } + + *final_reg_gsr = reg_gsr; + return 0; +} + +int mc_init(void) { int error = 0; - int timeout = 200000; + int portal_id = 0; struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; u64 mc_ram_addr; - u64 mc_dpl_offset; u32 reg_gsr; - u32 mc_fw_boot_status; - void *dpl_fdt_hdr; - int dpl_size; + u32 reg_mcfbalr; +#ifndef CONFIG_SYS_LS_MC_FW_IN_DDR const void *raw_image_addr; size_t raw_image_size = 0; - struct fsl_mc_io mc_io; - int portal_id; +#endif struct mc_version mc_ver_info; + u64 mc_ram_aligned_base_addr; + u8 mc_ram_num_256mb_blocks; + size_t mc_ram_size = mc_get_dram_block_size(); /* * The MC private DRAM block was already carved at the end of DRAM @@ -112,6 +403,20 @@ int mc_init(bd_t *bis) gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; } +#ifdef CONFIG_FSL_DEBUG_SERVER + /* + * FIXME: I don't think this is right. See get_dram_size_to_hide() + */ + mc_ram_addr -= debug_server_get_dram_block_size(); +#endif + + error = calculate_mc_private_ram_params(mc_ram_addr, + mc_ram_size, + &mc_ram_aligned_base_addr, + &mc_ram_num_256mb_blocks); + if (error != 0) + goto out; + /* * Management Complex cores should be held at reset out of POR. * U-boot should be the first software to touch MC. To be safe, @@ -127,6 +432,9 @@ int mc_init(bd_t *bis) out_le32(&mc_ccsr_regs->reg_gcr1, 0); dmb(); +#ifdef CONFIG_SYS_LS_MC_FW_IN_DDR + printf("MC firmware is preloaded to %#llx\n", mc_ram_addr); +#else error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size); if (error != 0) goto out; @@ -135,83 +443,34 @@ int mc_init(bd_t *bis) */ mc_copy_image("MC Firmware", (u64)raw_image_addr, raw_image_size, mc_ram_addr); - - /* - * Get address and size of the DPL blob stored in flash: - */ -#ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR - dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR; -#else -#error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined" #endif + dump_ram_words("firmware", (void *)mc_ram_addr); - error = fdt_check_header(dpl_fdt_hdr); - if (error != 0) { - printf("fsl-mc: ERROR: Bad DPL image (bad header)\n"); - goto out; - } - - dpl_size = fdt_totalsize(dpl_fdt_hdr); - if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) { - printf("fsl-mc: ERROR: Bad DPL image (too large: %d)\n", - dpl_size); - error = -EINVAL; + error = load_mc_dpc(mc_ram_addr, mc_ram_size); + if (error != 0) goto out; - } - /* - * Calculate offset in the MC private DRAM block at which the MC DPL - * blob is to be placed: - */ -#ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET - BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 || - CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff); - - mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET; -#else - mc_dpl_offset = mc_get_dram_block_size() - - roundup(CONFIG_SYS_LS_MC_DPL_MAX_LENGTH, 4096); - - if ((mc_dpl_offset & 0x3) != 0 || mc_dpl_offset > 0xffffffff) { - printf("%s: Invalid MC DPL offset: %llu\n", - __func__, mc_dpl_offset); - error = -EINVAL; + error = load_mc_dpl(mc_ram_addr, mc_ram_size); + if (error != 0) goto out; - } -#endif - - /* - * Load the MC DPL blob at the far end of the MC private DRAM block: - * - * TODO: Should we place the DPL at a different location to match - * assumptions of MC firmware about its memory layout? - */ - mc_copy_image("MC DPL blob", - (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset); debug("mc_ccsr_regs %p\n", mc_ccsr_regs); + dump_mc_ccsr_regs(mc_ccsr_regs); /* - * Tell MC where the MC Firmware image was loaded in DDR: + * Tell MC what is the address range of the DRAM block assigned to it: */ - out_le32(&mc_ccsr_regs->reg_mcfbalr, (u32)mc_ram_addr); - out_le32(&mc_ccsr_regs->reg_mcfbahr, (u32)((u64)mc_ram_addr >> 32)); + reg_mcfbalr = (u32)mc_ram_aligned_base_addr | + (mc_ram_num_256mb_blocks - 1); + out_le32(&mc_ccsr_regs->reg_mcfbalr, reg_mcfbalr); + out_le32(&mc_ccsr_regs->reg_mcfbahr, + (u32)(mc_ram_aligned_base_addr >> 32)); out_le32(&mc_ccsr_regs->reg_mcfapr, MCFAPR_BYPASS_ICID_MASK); /* - * Tell MC where the DPL blob was loaded in DDR, by indicating - * its offset relative to the beginning of the DDR block - * allocated to the MC firmware. The MC firmware is responsible - * for checking that there is no overlap between the DPL blob - * and the runtime heap and stack of the MC firmware itself. - * - * NOTE: bits [31:2] of this offset need to be stored in bits [29:0] of - * the GSR MC CCSR register. So, this offset is assumed to be 4-byte - * aligned. - * Care must be taken not to write 1s into bits 31 and 30 of the GSR in - * this case as the SoC COP or PIC will be signaled. + * Tell the MC that we want delayed DPL deployment. */ - out_le32(&mc_ccsr_regs->reg_gsr, (u32)(mc_dpl_offset >> 2)); + out_le32(&mc_ccsr_regs->reg_gsr, 0xDD00); printf("\nfsl-mc: Booting Management Complex ...\n"); @@ -219,38 +478,9 @@ int mc_init(bd_t *bis) * Deassert reset and release MC core 0 to run */ out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST); - dmb(); - debug("Polling mc_ccsr_regs->reg_gsr ...\n"); - - for (;;) { - reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr); - mc_fw_boot_status = (reg_gsr & GSR_FS_MASK); - if (mc_fw_boot_status & 0x1) - break; - - udelay(1000); /* throttle polling */ - if (timeout-- <= 0) - break; - } - - if (timeout <= 0) { - printf("fsl-mc: timeout booting management complex firmware\n"); - - /* TODO: Get an error status from an MC CCSR register */ - error = -ETIMEDOUT; + error = wait_for_mc(true, ®_gsr); + if (error != 0) goto out; - } - - if (mc_fw_boot_status != 0x1) { - /* - * TODO: Identify critical errors from the GSR register's FS - * field and for those errors, set error to -ENODEV or other - * appropriate errno, so that the status property is set to - * failure in the fsl,dprc device tree node. - */ - printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n", - reg_gsr); - } /* * TODO: need to obtain the portal_id for the root container from the @@ -259,13 +489,20 @@ int mc_init(bd_t *bis) portal_id = 0; /* - * Check that the MC firmware is responding portal commands: + * Initialize the global default MC portal + * And check that the MC firmware is responding portal commands: */ - mc_io.mmio_regs = SOC_MC_PORTAL_ADDR(portal_id); + dflt_mc_io = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io)); + if (!dflt_mc_io) { + printf(" No memory: malloc() failed\n"); + return -ENOMEM; + } + + dflt_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(portal_id); debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n", - portal_id, mc_io.mmio_regs); + portal_id, dflt_mc_io->mmio_regs); - error = mc_get_version(&mc_io, &mc_ver_info); + error = mc_get_version(dflt_mc_io, &mc_ver_info); if (error != 0) { printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n", error); @@ -282,7 +519,16 @@ int mc_init(bd_t *bis) printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n", mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision, - mc_fw_boot_status); + reg_gsr & GSR_FS_MASK); + + /* + * Tell the MC to deploy the DPL: + */ + out_le32(&mc_ccsr_regs->reg_gsr, 0x0); + printf("\nfsl-mc: Deploying data path layout ...\n"); + error = wait_for_mc(false, ®_gsr); + if (error != 0) + goto out; out: if (error != 0) mc_boot_status = -error; @@ -299,12 +545,242 @@ int get_mc_boot_status(void) /** * Return the actual size of the MC private DRAM block. - * - * NOTE: For now this function always returns the minimum required size, - * However, in the future, the actual size may be obtained from an environment - * variable. */ unsigned long mc_get_dram_block_size(void) { - return CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; + unsigned long dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; + + char *dram_block_size_env_var = getenv(MC_MEM_SIZE_ENV_VAR); + + if (dram_block_size_env_var) { + dram_block_size = simple_strtoul(dram_block_size_env_var, NULL, + 10); + + if (dram_block_size < CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE) { + printf("fsl-mc: WARNING: Invalid value for \'" + MC_MEM_SIZE_ENV_VAR + "\' environment variable: %lu\n", + dram_block_size); + + dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; + } + } + + return dram_block_size; +} + +int dpio_init(struct dprc_obj_desc obj_desc) +{ + struct qbman_swp_desc p_des; + struct dpio_attr attr; + int err = 0; + + dflt_dpio = (struct fsl_dpio_obj *)malloc(sizeof(struct fsl_dpio_obj)); + if (!dflt_dpio) { + printf(" No memory: malloc() failed\n"); + return -ENOMEM; + } + + dflt_dpio->dpio_id = obj_desc.id; + + err = dpio_open(dflt_mc_io, obj_desc.id, &dflt_dpio_handle); + if (err) { + printf("dpio_open() failed\n"); + goto err_open; + } + + err = dpio_get_attributes(dflt_mc_io, dflt_dpio_handle, &attr); + if (err) { + printf("dpio_get_attributes() failed %d\n", err); + goto err_get_attr; + } + + err = dpio_enable(dflt_mc_io, dflt_dpio_handle); + if (err) { + printf("dpio_enable() failed %d\n", err); + goto err_get_enable; + } + debug("ce_paddr=0x%llx, ci_paddr=0x%llx, portalid=%d, prios=%d\n", + attr.qbman_portal_ce_paddr, + attr.qbman_portal_ci_paddr, + attr.qbman_portal_id, + attr.num_priorities); + + p_des.cena_bar = (void *)attr.qbman_portal_ce_paddr; + p_des.cinh_bar = (void *)attr.qbman_portal_ci_paddr; + + dflt_dpio->sw_portal = qbman_swp_init(&p_des); + if (dflt_dpio->sw_portal == NULL) { + printf("qbman_swp_init() failed\n"); + goto err_get_swp_init; + } + return 0; + +err_get_swp_init: +err_get_enable: + dpio_disable(dflt_mc_io, dflt_dpio_handle); +err_get_attr: + dpio_close(dflt_mc_io, dflt_dpio_handle); +err_open: + free(dflt_dpio); + return err; +} + +int dpbp_init(struct dprc_obj_desc obj_desc) +{ + dflt_dpbp = (struct fsl_dpbp_obj *)malloc(sizeof(struct fsl_dpbp_obj)); + if (!dflt_dpbp) { + printf(" No memory: malloc() failed\n"); + return -ENOMEM; + } + dflt_dpbp->dpbp_attr.id = obj_desc.id; + + return 0; +} + +int dprc_init_container_obj(struct dprc_obj_desc obj_desc, uint16_t dprc_handle) +{ + int error = 0, state = 0; + struct dprc_endpoint dpni_endpoint, dpmac_endpoint; + if (!strcmp(obj_desc.type, "dpbp")) { + if (!dflt_dpbp) { + error = dpbp_init(obj_desc); + if (error < 0) + printf("dpbp_init failed\n"); + } + } else if (!strcmp(obj_desc.type, "dpio")) { + if (!dflt_dpio) { + error = dpio_init(obj_desc); + if (error < 0) + printf("dpio_init failed\n"); + } + } else if (!strcmp(obj_desc.type, "dpni")) { + strcpy(dpni_endpoint.type, obj_desc.type); + dpni_endpoint.id = obj_desc.id; + error = dprc_get_connection(dflt_mc_io, dprc_handle, + &dpni_endpoint, &dpmac_endpoint, &state); + if (!strcmp(dpmac_endpoint.type, "dpmac")) + error = ldpaa_eth_init(obj_desc); + if (error < 0) + printf("ldpaa_eth_init failed\n"); + } + + return error; +} + +int dprc_scan_container_obj(uint16_t dprc_handle, char *obj_type, int i) +{ + int error = 0; + struct dprc_obj_desc obj_desc; + + memset((void *)&obj_desc, 0x00, sizeof(struct dprc_obj_desc)); + + error = dprc_get_obj(dflt_mc_io, dprc_handle, + i, &obj_desc); + if (error < 0) { + printf("dprc_get_obj(i=%d) failed: %d\n", + i, error); + return error; + } + + if (!strcmp(obj_desc.type, obj_type)) { + debug("Discovered object: type %s, id %d, req %s\n", + obj_desc.type, obj_desc.id, obj_type); + + error = dprc_init_container_obj(obj_desc, dprc_handle); + if (error < 0) { + printf("dprc_init_container_obj(i=%d) failed: %d\n", + i, error); + return error; + } + } + + return error; +} + +int fsl_mc_ldpaa_init(bd_t *bis) +{ + int i, error = 0; + int dprc_opened = 0, container_id; + int num_child_objects = 0; + + error = mc_init(); + if (error < 0) + goto error; + + error = dprc_get_container_id(dflt_mc_io, &container_id); + if (error < 0) { + printf("dprc_get_container_id() failed: %d\n", error); + goto error; + } + + debug("fsl-mc: Container id=0x%x\n", container_id); + + error = dprc_open(dflt_mc_io, container_id, &dflt_dprc_handle); + if (error < 0) { + printf("dprc_open() failed: %d\n", error); + goto error; + } + dprc_opened = true; + + error = dprc_get_obj_count(dflt_mc_io, + dflt_dprc_handle, + &num_child_objects); + if (error < 0) { + printf("dprc_get_obj_count() failed: %d\n", error); + goto error; + } + debug("Total child in container %d = %d\n", container_id, + num_child_objects); + + if (num_child_objects != 0) { + /* + * Discover objects currently in the DPRC container in the MC: + */ + for (i = 0; i < num_child_objects; i++) + error = dprc_scan_container_obj(dflt_dprc_handle, + "dpbp", i); + + for (i = 0; i < num_child_objects; i++) + error = dprc_scan_container_obj(dflt_dprc_handle, + "dpio", i); + + for (i = 0; i < num_child_objects; i++) + error = dprc_scan_container_obj(dflt_dprc_handle, + "dpni", i); + } +error: + if (dprc_opened) + dprc_close(dflt_mc_io, dflt_dprc_handle); + + return error; +} + +void fsl_mc_ldpaa_exit(bd_t *bis) +{ + int err; + + if (get_mc_boot_status() == 0) { + err = dpio_disable(dflt_mc_io, dflt_dpio_handle); + if (err < 0) { + printf("dpio_disable() failed: %d\n", err); + return; + } + err = dpio_reset(dflt_mc_io, dflt_dpio_handle); + if (err < 0) { + printf("dpio_reset() failed: %d\n", err); + return; + } + err = dpio_close(dflt_mc_io, dflt_dpio_handle); + if (err < 0) { + printf("dpio_close() failed: %d\n", err); + return; + } + + free(dflt_dpio); + free(dflt_dpbp); + } + + if (dflt_mc_io) + free(dflt_mc_io); } diff --git a/drivers/net/fsl-mc/mc_sys.c b/drivers/net/fsl-mc/mc_sys.c index 7c8e003..3fc1f98 100644 --- a/drivers/net/fsl-mc/mc_sys.c +++ b/drivers/net/fsl-mc/mc_sys.c @@ -1,7 +1,7 @@ /* * Freescale Layerscape MC I/O wrapper * - * Copyright (C) 2014 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. * Author: German Rivera <German.Rivera@freescale.com> * * SPDX-License-Identifier: GPL-2.0+ @@ -32,7 +32,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) { enum mc_cmd_status status; - int timeout = 2000; + int timeout = 6000; mc_write_command(mc_io->mmio_regs, cmd); @@ -52,7 +52,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, if (status != MC_CMD_STATUS_OK) { printf("Error: MC command failed (portal: %p, obj handle: %#x, command: %#x, status: %#x)\n", mc_io->mmio_regs, - (unsigned int)MC_CMD_HDR_READ_AUTHID(cmd->header), + (unsigned int)MC_CMD_HDR_READ_TOKEN(cmd->header), (unsigned int)MC_CMD_HDR_READ_CMDID(cmd->header), (unsigned int)status); diff --git a/drivers/net/ldpaa_eth/Makefile b/drivers/net/ldpaa_eth/Makefile new file mode 100644 index 0000000..c37633f --- /dev/null +++ b/drivers/net/ldpaa_eth/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2014 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += ldpaa_wriop.o +obj-y += ldpaa_eth.o +obj-$(CONFIG_LS2085A) += ls2085a.o diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c new file mode 100644 index 0000000..d4be1ba --- /dev/null +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/types.h> +#include <malloc.h> +#include <net.h> +#include <hwconfig.h> +#include <phy.h> +#include <linux/compat.h> + +#include "ldpaa_eth.h" + +#undef CONFIG_PHYLIB +static int init_phy(struct eth_device *dev) +{ + /*TODO for external PHY */ + + return 0; +} + +static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv, + const struct dpaa_fd *fd) +{ + u64 fd_addr; + uint16_t fd_offset; + uint32_t fd_length; + struct ldpaa_fas *fas; + uint32_t status, err; + struct qbman_release_desc releasedesc; + struct qbman_swp *swp = dflt_dpio->sw_portal; + + fd_addr = ldpaa_fd_get_addr(fd); + fd_offset = ldpaa_fd_get_offset(fd); + fd_length = ldpaa_fd_get_len(fd); + + debug("Rx frame:data addr=0x%p size=0x%x\n", (u64 *)fd_addr, fd_length); + + if (fd->simple.frc & LDPAA_FD_FRC_FASV) { + /* Read the frame annotation status word and check for errors */ + fas = (struct ldpaa_fas *) + ((uint8_t *)(fd_addr) + + priv->buf_layout.private_data_size); + status = le32_to_cpu(fas->status); + if (status & LDPAA_ETH_RX_ERR_MASK) { + printf("Rx frame error(s): 0x%08x\n", + status & LDPAA_ETH_RX_ERR_MASK); + goto error; + } else if (status & LDPAA_ETH_RX_UNSUPP_MASK) { + printf("Unsupported feature in bitmask: 0x%08x\n", + status & LDPAA_ETH_RX_UNSUPP_MASK); + goto error; + } + } + + debug("Rx frame: To Upper layer\n"); + net_process_received_packet((uint8_t *)(fd_addr) + fd_offset, + fd_length); + +error: + flush_dcache_range(fd_addr, fd_addr + LDPAA_ETH_RX_BUFFER_SIZE); + qbman_release_desc_clear(&releasedesc); + qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid); + do { + /* Release buffer into the QBMAN */ + err = qbman_swp_release(swp, &releasedesc, &fd_addr, 1); + } while (err == -EBUSY); + return; +} + +static int ldpaa_eth_pull_dequeue_rx(struct eth_device *dev) +{ + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv; + const struct ldpaa_dq *dq; + const struct dpaa_fd *fd; + int i = 5, err = 0, status, loop = 20; + static struct qbman_pull_desc pulldesc; + struct qbman_swp *swp = dflt_dpio->sw_portal; + + while (--i) { + qbman_pull_desc_clear(&pulldesc); + qbman_pull_desc_set_numframes(&pulldesc, 1); + qbman_pull_desc_set_fq(&pulldesc, priv->rx_dflt_fqid); + + err = qbman_swp_pull(swp, &pulldesc); + if (err < 0) { + printf("Dequeue frames error:0x%08x\n", err); + continue; + } + + do { + loop--; + dq = qbman_swp_dqrr_next(swp); + + if (!loop) + break; + } while (!dq); + + if (dq) { + /* Check for valid frame. If not sent a consume + * confirmation to QBMAN otherwise give it to NADK + * application and then send consume confirmation to + * QBMAN. + */ + status = (uint8_t)ldpaa_dq_flags(dq); + if ((status & LDPAA_DQ_STAT_VALIDFRAME) == 0) { + debug("Dequeue RX frames:"); + debug("No frame delivered\n"); + + qbman_swp_dqrr_consume(swp, dq); + break; + } + + fd = ldpaa_dq_fd(dq); + + /* Obtain FD and process it */ + ldpaa_eth_rx(priv, fd); + qbman_swp_dqrr_consume(swp, dq); + break; + } + } + + return err; +} + +static void ldpaa_eth_tx_conf(struct ldpaa_eth_priv *priv, + const struct dpaa_fd *fd) +{ + uint64_t fd_addr; + struct ldpaa_fas *fas; + uint32_t status, err; + struct qbman_release_desc releasedesc; + struct qbman_swp *swp = dflt_dpio->sw_portal; + + fd_addr = ldpaa_fd_get_addr(fd); + + + debug("TX Conf frame:data addr=0x%p\n", (u64 *)fd_addr); + + /* Check the status from the Frame Annotation */ + if (fd->simple.frc & LDPAA_FD_FRC_FASV) { + fas = (struct ldpaa_fas *) + ((uint8_t *)(fd_addr) + + priv->buf_layout.private_data_size); + status = le32_to_cpu(fas->status); + if (status & LDPAA_ETH_TXCONF_ERR_MASK) { + printf("TxConf frame error(s): 0x%08x\n", + status & LDPAA_ETH_TXCONF_ERR_MASK); + } + } + + qbman_release_desc_clear(&releasedesc); + qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid); + do { + /* Release buffer into the QBMAN */ + err = qbman_swp_release(swp, &releasedesc, &fd_addr, 1); + } while (err == -EBUSY); +} + +static int ldpaa_eth_pull_dequeue_tx_conf(struct ldpaa_eth_priv *priv) +{ + const struct ldpaa_dq *dq; + const struct dpaa_fd *fd; + int err = 0; + int i = 5, status, loop = 20; + static struct qbman_pull_desc pulldesc; + struct qbman_swp *swp = dflt_dpio->sw_portal; + + while (--i) { + qbman_pull_desc_clear(&pulldesc); + qbman_pull_desc_set_numframes(&pulldesc, 1); + qbman_pull_desc_set_fq(&pulldesc, priv->tx_conf_fqid); + + err = qbman_swp_pull(swp, &pulldesc); + if (err < 0) { + printf("Dequeue TX conf frames error:0x%08x\n", err); + continue; + } + + do { + loop--; + dq = qbman_swp_dqrr_next(swp); + + if (!loop) + break; + } while (!dq); + + if (dq) { + /* Check for valid frame. If not sent a consume + * confirmation to QBMAN otherwise give it to NADK + * application and then send consume confirmation to + * QBMAN. + */ + status = (uint8_t)ldpaa_dq_flags(dq); + if ((status & LDPAA_DQ_STAT_VALIDFRAME) == 0) { + debug("Dequeue TX conf frames:"); + debug("No frame is delivered\n"); + + qbman_swp_dqrr_consume(swp, dq); + break; + } + fd = ldpaa_dq_fd(dq); + + ldpaa_eth_tx_conf(priv, fd); + qbman_swp_dqrr_consume(swp, dq); + break; + } + } + + return err; +} + +static int ldpaa_eth_tx(struct eth_device *net_dev, void *buf, int len) +{ + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; + struct dpaa_fd fd; + u64 buffer_start; + int data_offset, err; + struct qbman_swp *swp = dflt_dpio->sw_portal; + struct qbman_eq_desc ed; + + /* Setup the FD fields */ + memset(&fd, 0, sizeof(fd)); + + data_offset = priv->tx_data_offset; + + do { + err = qbman_swp_acquire(dflt_dpio->sw_portal, + dflt_dpbp->dpbp_attr.bpid, + &buffer_start, 1); + } while (err == -EBUSY); + + if (err < 0) { + printf("qbman_swp_acquire() failed\n"); + return -ENOMEM; + } + + debug("TX data: malloc buffer start=0x%p\n", (u64 *)buffer_start); + + memcpy(((uint8_t *)(buffer_start) + data_offset), buf, len); + + flush_dcache_range(buffer_start, buffer_start + + LDPAA_ETH_RX_BUFFER_SIZE); + + ldpaa_fd_set_addr(&fd, (u64)buffer_start); + ldpaa_fd_set_offset(&fd, (uint16_t)(data_offset)); + ldpaa_fd_set_bpid(&fd, dflt_dpbp->dpbp_attr.bpid); + ldpaa_fd_set_len(&fd, len); + + fd.simple.ctrl = LDPAA_FD_CTRL_ASAL | LDPAA_FD_CTRL_PTA | + LDPAA_FD_CTRL_PTV1; + + qbman_eq_desc_clear(&ed); + qbman_eq_desc_set_no_orp(&ed, 0); + qbman_eq_desc_set_qd(&ed, priv->tx_qdid, priv->tx_flow_id, 0); + err = qbman_swp_enqueue(swp, &ed, (const struct qbman_fd *)(&fd)); + if (err < 0) + printf("error enqueueing Tx frame\n"); + + mdelay(1); + + err = ldpaa_eth_pull_dequeue_tx_conf(priv); + if (err < 0) + printf("error Tx Conf frame\n"); + + return err; +} + +static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) +{ + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; + struct dpni_queue_attr rx_queue_attr; + struct dpni_tx_flow_attr tx_flow_attr; + uint8_t mac_addr[6]; + int err; + + if (net_dev->state == ETH_STATE_ACTIVE) + return 0; + + /* DPNI initialization */ + err = ldpaa_dpni_setup(priv); + if (err < 0) + goto err_dpni_setup; + + err = ldpaa_dpbp_setup(); + if (err < 0) + goto err_dpbp_setup; + + /* DPNI binding DPBP */ + err = ldpaa_dpni_bind(priv); + if (err) + goto err_bind; + + err = dpni_get_primary_mac_addr(dflt_mc_io, priv->dpni_handle, + mac_addr); + if (err) { + printf("dpni_get_primary_mac_addr() failed\n"); + return err; + } + + memcpy(net_dev->enetaddr, mac_addr, 0x6); + + /* setup the MAC address */ + if (net_dev->enetaddr[0] & 0x01) { + printf("%s: MacAddress is multcast address\n", __func__); + return 1; + } + +#ifdef CONFIG_PHYLIB + /* TODO Check this path */ + err = phy_startup(priv->phydev); + if (err) { + printf("%s: Could not initialize\n", priv->phydev->dev->name); + return err; + } +#else + priv->phydev->speed = SPEED_1000; + priv->phydev->link = 1; + priv->phydev->duplex = DUPLEX_FULL; +#endif + + err = dpni_enable(dflt_mc_io, priv->dpni_handle); + if (err < 0) { + printf("dpni_enable() failed\n"); + return err; + } + + /* TODO: support multiple Rx flows */ + err = dpni_get_rx_flow(dflt_mc_io, priv->dpni_handle, 0, 0, + &rx_queue_attr); + if (err) { + printf("dpni_get_rx_flow() failed\n"); + goto err_rx_flow; + } + + priv->rx_dflt_fqid = rx_queue_attr.fqid; + + err = dpni_get_qdid(dflt_mc_io, priv->dpni_handle, &priv->tx_qdid); + if (err) { + printf("dpni_get_qdid() failed\n"); + goto err_qdid; + } + + err = dpni_get_tx_flow(dflt_mc_io, priv->dpni_handle, priv->tx_flow_id, + &tx_flow_attr); + if (err) { + printf("dpni_get_tx_flow() failed\n"); + goto err_tx_flow; + } + + priv->tx_conf_fqid = tx_flow_attr.conf_err_attr.queue_attr.fqid; + + if (!priv->phydev->link) + printf("%s: No link.\n", priv->phydev->dev->name); + + return priv->phydev->link ? 0 : -1; + +err_tx_flow: +err_qdid: +err_rx_flow: + dpni_disable(dflt_mc_io, priv->dpni_handle); +err_bind: + ldpaa_dpbp_free(); +err_dpbp_setup: + dpni_close(dflt_mc_io, priv->dpni_handle); +err_dpni_setup: + return err; +} + +static void ldpaa_eth_stop(struct eth_device *net_dev) +{ + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; + int err = 0; + + if ((net_dev->state == ETH_STATE_PASSIVE) || + (net_dev->state == ETH_STATE_INIT)) + return; + /* Stop Tx and Rx traffic */ + err = dpni_disable(dflt_mc_io, priv->dpni_handle); + if (err < 0) + printf("dpni_disable() failed\n"); + +#ifdef CONFIG_PHYLIB + phy_shutdown(priv->phydev); +#endif + + ldpaa_dpbp_free(); + dpni_reset(dflt_mc_io, priv->dpni_handle); + dpni_close(dflt_mc_io, priv->dpni_handle); +} + +static void ldpaa_dpbp_drain_cnt(int count) +{ + uint64_t buf_array[7]; + void *addr; + int ret, i; + + BUG_ON(count > 7); + + do { + ret = qbman_swp_acquire(dflt_dpio->sw_portal, + dflt_dpbp->dpbp_attr.bpid, + buf_array, count); + if (ret < 0) { + printf("qbman_swp_acquire() failed\n"); + return; + } + for (i = 0; i < ret; i++) { + addr = (void *)buf_array[i]; + debug("Free: buffer addr =0x%p\n", addr); + free(addr); + } + } while (ret); +} + +static void ldpaa_dpbp_drain(void) +{ + int i; + for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7) + ldpaa_dpbp_drain_cnt(7); +} + +static int ldpaa_bp_add_7(uint16_t bpid) +{ + uint64_t buf_array[7]; + u8 *addr; + int i; + struct qbman_release_desc rd; + + for (i = 0; i < 7; i++) { + addr = memalign(L1_CACHE_BYTES, LDPAA_ETH_RX_BUFFER_SIZE); + if (!addr) { + printf("addr allocation failed\n"); + goto err_alloc; + } + memset(addr, 0x00, LDPAA_ETH_RX_BUFFER_SIZE); + flush_dcache_range((u64)addr, + (u64)(addr + LDPAA_ETH_RX_BUFFER_SIZE)); + + buf_array[i] = (uint64_t)addr; + debug("Release: buffer addr =0x%p\n", addr); + } + +release_bufs: + /* In case the portal is busy, retry until successful. + * This function is guaranteed to succeed in a reasonable amount + * of time. + */ + + do { + mdelay(1); + qbman_release_desc_clear(&rd); + qbman_release_desc_set_bpid(&rd, bpid); + } while (qbman_swp_release(dflt_dpio->sw_portal, &rd, buf_array, i)); + + return i; + +err_alloc: + if (i) + goto release_bufs; + + return 0; +} + +static int ldpaa_dpbp_seed(uint16_t bpid) +{ + int i; + int count; + + for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7) { + count = ldpaa_bp_add_7(bpid); + if (count < 7) + printf("Buffer Seed= %d\n", count); + } + + return 0; +} + +static int ldpaa_dpbp_setup(void) +{ + int err; + + err = dpbp_open(dflt_mc_io, dflt_dpbp->dpbp_attr.id, + &dflt_dpbp->dpbp_handle); + if (err) { + printf("dpbp_open() failed\n"); + goto err_open; + } + + err = dpbp_enable(dflt_mc_io, dflt_dpbp->dpbp_handle); + if (err) { + printf("dpbp_enable() failed\n"); + goto err_enable; + } + + err = dpbp_get_attributes(dflt_mc_io, dflt_dpbp->dpbp_handle, + &dflt_dpbp->dpbp_attr); + if (err) { + printf("dpbp_get_attributes() failed\n"); + goto err_get_attr; + } + + err = ldpaa_dpbp_seed(dflt_dpbp->dpbp_attr.bpid); + if (err) { + printf("Buffer seeding failed for DPBP %d (bpid=%d)\n", + dflt_dpbp->dpbp_attr.id, dflt_dpbp->dpbp_attr.bpid); + goto err_seed; + } + + return 0; + +err_seed: +err_get_attr: + dpbp_disable(dflt_mc_io, dflt_dpbp->dpbp_handle); +err_enable: + dpbp_close(dflt_mc_io, dflt_dpbp->dpbp_handle); +err_open: + return err; +} + +static void ldpaa_dpbp_free(void) +{ + ldpaa_dpbp_drain(); + dpbp_disable(dflt_mc_io, dflt_dpbp->dpbp_handle); + dpbp_reset(dflt_mc_io, dflt_dpbp->dpbp_handle); + dpbp_close(dflt_mc_io, dflt_dpbp->dpbp_handle); +} + +static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv) +{ + int err; + + /* and get a handle for the DPNI this interface is associate with */ + err = dpni_open(dflt_mc_io, priv->dpni_id, &priv->dpni_handle); + if (err) { + printf("dpni_open() failed\n"); + goto err_open; + } + + err = dpni_get_attributes(dflt_mc_io, priv->dpni_handle, + &priv->dpni_attrs); + if (err) { + printf("dpni_get_attributes() failed (err=%d)\n", err); + goto err_get_attr; + } + + /* Configure our buffers' layout */ + priv->buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | + DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | + DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; + priv->buf_layout.pass_parser_result = true; + priv->buf_layout.pass_frame_status = true; + priv->buf_layout.private_data_size = LDPAA_ETH_SWA_SIZE; + /* ...rx, ... */ + err = dpni_set_rx_buffer_layout(dflt_mc_io, priv->dpni_handle, + &priv->buf_layout); + if (err) { + printf("dpni_set_rx_buffer_layout() failed"); + goto err_buf_layout; + } + + /* ... tx, ... */ + priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PARSER_RESULT; + err = dpni_set_tx_buffer_layout(dflt_mc_io, priv->dpni_handle, + &priv->buf_layout); + if (err) { + printf("dpni_set_tx_buffer_layout() failed"); + goto err_buf_layout; + } + + /* ... tx-confirm. */ + priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; + err = dpni_set_tx_conf_buffer_layout(dflt_mc_io, priv->dpni_handle, + &priv->buf_layout); + if (err) { + printf("dpni_set_tx_conf_buffer_layout() failed"); + goto err_buf_layout; + } + + /* Now that we've set our tx buffer layout, retrieve the minimum + * required tx data offset. + */ + err = dpni_get_tx_data_offset(dflt_mc_io, priv->dpni_handle, + &priv->tx_data_offset); + if (err) { + printf("dpni_get_tx_data_offset() failed\n"); + goto err_data_offset; + } + + /* Warn in case TX data offset is not multiple of 64 bytes. */ + WARN_ON(priv->tx_data_offset % 64); + + /* Accomodate SWA space. */ + priv->tx_data_offset += LDPAA_ETH_SWA_SIZE; + debug("priv->tx_data_offset=%d\n", priv->tx_data_offset); + + return 0; + +err_data_offset: +err_buf_layout: +err_get_attr: + dpni_close(dflt_mc_io, priv->dpni_handle); +err_open: + return err; +} + +static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) +{ + struct dpni_pools_cfg pools_params; + struct dpni_tx_flow_cfg dflt_tx_flow; + int err = 0; + + pools_params.num_dpbp = 1; + pools_params.pools[0].dpbp_id = (uint16_t)dflt_dpbp->dpbp_attr.id; + pools_params.pools[0].buffer_size = LDPAA_ETH_RX_BUFFER_SIZE; + err = dpni_set_pools(dflt_mc_io, priv->dpni_handle, &pools_params); + if (err) { + printf("dpni_set_pools() failed\n"); + return err; + } + + priv->tx_flow_id = DPNI_NEW_FLOW_ID; + memset(&dflt_tx_flow, 0, sizeof(dflt_tx_flow)); + + err = dpni_set_tx_flow(dflt_mc_io, priv->dpni_handle, + &priv->tx_flow_id, &dflt_tx_flow); + if (err) { + printf("dpni_set_tx_flow() failed\n"); + return err; + } + + return 0; +} + +static int ldpaa_eth_netdev_init(struct eth_device *net_dev) +{ + int err; + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; + + sprintf(net_dev->name, "DPNI%d", priv->dpni_id); + + net_dev->iobase = 0; + net_dev->init = ldpaa_eth_open; + net_dev->halt = ldpaa_eth_stop; + net_dev->send = ldpaa_eth_tx; + net_dev->recv = ldpaa_eth_pull_dequeue_rx; +/* + TODO: PHY MDIO information + priv->bus = info->bus; + priv->phyaddr = info->phy_addr; + priv->enet_if = info->enet_if; +*/ + + if (init_phy(net_dev)) + return 0; + + err = eth_register(net_dev); + if (err < 0) { + printf("eth_register() = %d\n", err); + return err; + } + + return 0; +} + +int ldpaa_eth_init(struct dprc_obj_desc obj_desc) +{ + struct eth_device *net_dev = NULL; + struct ldpaa_eth_priv *priv = NULL; + int err = 0; + + + /* Net device */ + net_dev = (struct eth_device *)malloc(sizeof(struct eth_device)); + if (!net_dev) { + printf("eth_device malloc() failed\n"); + return -ENOMEM; + } + memset(net_dev, 0, sizeof(struct eth_device)); + + /* alloc the ldpaa ethernet private struct */ + priv = (struct ldpaa_eth_priv *)malloc(sizeof(struct ldpaa_eth_priv)); + if (!priv) { + printf("ldpaa_eth_priv malloc() failed\n"); + return -ENOMEM; + } + memset(priv, 0, sizeof(struct ldpaa_eth_priv)); + + net_dev->priv = (void *)priv; + priv->net_dev = (struct eth_device *)net_dev; + priv->dpni_id = obj_desc.id; + + err = ldpaa_eth_netdev_init(net_dev); + if (err) + goto err_netdev_init; + + debug("ldpaa ethernet: Probed interface %s\n", net_dev->name); + return 0; + +err_netdev_init: + free(priv); + net_dev->priv = NULL; + free(net_dev); + + return err; +} diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.h b/drivers/net/ldpaa_eth/ldpaa_eth.h new file mode 100644 index 0000000..3107ab6 --- /dev/null +++ b/drivers/net/ldpaa_eth/ldpaa_eth.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __LDPAA_ETH_H +#define __LDPAA_ETH_H + +#include <linux/netdevice.h> +#include <fsl-mc/fsl_mc.h> +#include <fsl-mc/fsl_dpaa_fd.h> +#include <fsl-mc/fsl_dprc.h> +#include <fsl-mc/fsl_dpni.h> +#include <fsl-mc/fsl_dpbp.h> +#include <fsl-mc/fsl_dpio.h> +#include <fsl-mc/fsl_qbman_portal.h> +#include <fsl-mc/fsl_mc_private.h> + + +enum ldpaa_eth_type { + LDPAA_ETH_1G_E, + LDPAA_ETH_10G_E, +}; + +/* Arbitrary values for now, but we'll need to tune */ +#define LDPAA_ETH_NUM_BUFS (2 * 7) +#define LDPAA_ETH_REFILL_THRESH (LDPAA_ETH_NUM_BUFS/2) +#define LDPAA_ETH_RX_BUFFER_SIZE 2048 + +/* Hardware requires alignment for ingress/egress buffer addresses + * and ingress buffer lengths. + */ +#define LDPAA_ETH_BUF_ALIGN 64 + +/* So far we're only accomodating a skb backpointer in the frame's + * software annotation, but the hardware options are either 0 or 64. + */ +#define LDPAA_ETH_SWA_SIZE 64 + +/* Annotation valid bits in FD FRC */ +#define LDPAA_FD_FRC_FASV 0x8000 +#define LDPAA_FD_FRC_FAEADV 0x4000 +#define LDPAA_FD_FRC_FAPRV 0x2000 +#define LDPAA_FD_FRC_FAIADV 0x1000 +#define LDPAA_FD_FRC_FASWOV 0x0800 +#define LDPAA_FD_FRC_FAICFDV 0x0400 + +/* Annotation bits in FD CTRL */ +#define LDPAA_FD_CTRL_ASAL 0x00020000 /* ASAL = 128 */ +#define LDPAA_FD_CTRL_PTA 0x00800000 +#define LDPAA_FD_CTRL_PTV1 0x00400000 + +/* TODO: we may want to move this and other WRIOP related defines + * to a separate header + */ +/* Frame annotation status */ +struct ldpaa_fas { + u8 reserved; + u8 ppid; + __le16 ifpid; + __le32 status; +} __packed; + +/* Debug frame, otherwise supposed to be discarded */ +#define LDPAA_ETH_FAS_DISC 0x80000000 +/* MACSEC frame */ +#define LDPAA_ETH_FAS_MS 0x40000000 +#define LDPAA_ETH_FAS_PTP 0x08000000 +/* Ethernet multicast frame */ +#define LDPAA_ETH_FAS_MC 0x04000000 +/* Ethernet broadcast frame */ +#define LDPAA_ETH_FAS_BC 0x02000000 +#define LDPAA_ETH_FAS_KSE 0x00040000 +#define LDPAA_ETH_FAS_EOFHE 0x00020000 +#define LDPAA_ETH_FAS_MNLE 0x00010000 +#define LDPAA_ETH_FAS_TIDE 0x00008000 +#define LDPAA_ETH_FAS_PIEE 0x00004000 +/* Frame length error */ +#define LDPAA_ETH_FAS_FLE 0x00002000 +/* Frame physical error; our favourite pastime */ +#define LDPAA_ETH_FAS_FPE 0x00001000 +#define LDPAA_ETH_FAS_PTE 0x00000080 +#define LDPAA_ETH_FAS_ISP 0x00000040 +#define LDPAA_ETH_FAS_PHE 0x00000020 +#define LDPAA_ETH_FAS_BLE 0x00000010 +/* L3 csum validation performed */ +#define LDPAA_ETH_FAS_L3CV 0x00000008 +/* L3 csum error */ +#define LDPAA_ETH_FAS_L3CE 0x00000004 +/* L4 csum validation performed */ +#define LDPAA_ETH_FAS_L4CV 0x00000002 +/* L4 csum error */ +#define LDPAA_ETH_FAS_L4CE 0x00000001 +/* These bits always signal errors */ +#define LDPAA_ETH_RX_ERR_MASK (LDPAA_ETH_FAS_DISC | \ + LDPAA_ETH_FAS_KSE | \ + LDPAA_ETH_FAS_EOFHE | \ + LDPAA_ETH_FAS_MNLE | \ + LDPAA_ETH_FAS_TIDE | \ + LDPAA_ETH_FAS_PIEE | \ + LDPAA_ETH_FAS_FLE | \ + LDPAA_ETH_FAS_FPE | \ + LDPAA_ETH_FAS_PTE | \ + LDPAA_ETH_FAS_ISP | \ + LDPAA_ETH_FAS_PHE | \ + LDPAA_ETH_FAS_BLE | \ + LDPAA_ETH_FAS_L3CE | \ + LDPAA_ETH_FAS_L4CE) +/* Unsupported features in the ingress */ +#define LDPAA_ETH_RX_UNSUPP_MASK LDPAA_ETH_FAS_MS +/* TODO trim down the bitmask; not all of them apply to Tx-confirm */ +#define LDPAA_ETH_TXCONF_ERR_MASK (LDPAA_ETH_FAS_KSE | \ + LDPAA_ETH_FAS_EOFHE | \ + LDPAA_ETH_FAS_MNLE | \ + LDPAA_ETH_FAS_TIDE) + +struct ldpaa_eth_priv { + struct eth_device *net_dev; + int dpni_id; + uint16_t dpni_handle; + struct dpni_attr dpni_attrs; + /* Insofar as the MC is concerned, we're using one layout on all 3 types + * of buffers (Rx, Tx, Tx-Conf). + */ + struct dpni_buffer_layout buf_layout; + uint16_t tx_data_offset; + + uint32_t rx_dflt_fqid; + uint16_t tx_qdid; + uint32_t tx_conf_fqid; + uint16_t tx_flow_id; + + enum ldpaa_eth_type type; /* 1G or 10G ethernet */ + struct phy_device *phydev; +}; + +extern struct fsl_mc_io *dflt_mc_io; +extern struct fsl_dpbp_obj *dflt_dpbp; +extern struct fsl_dpio_obj *dflt_dpio; + +static void ldpaa_dpbp_drain_cnt(int count); +static void ldpaa_dpbp_drain(void); +static int ldpaa_dpbp_seed(uint16_t bpid); +static void ldpaa_dpbp_free(void); +static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv); +static int ldpaa_dpbp_setup(void); +static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv); +#endif /* __LDPAA_H */ diff --git a/drivers/net/ldpaa_eth/ldpaa_wriop.c b/drivers/net/ldpaa_eth/ldpaa_wriop.c new file mode 100644 index 0000000..926057a --- /dev/null +++ b/drivers/net/ldpaa_eth/ldpaa_wriop.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/types.h> +#include <malloc.h> +#include <net.h> +#include <linux/compat.h> +#include <asm/arch/fsl_serdes.h> +#include <fsl-mc/ldpaa_wriop.h> + +struct wriop_dpmac_info dpmac_info[NUM_WRIOP_PORTS]; + +__weak phy_interface_t wriop_dpmac_enet_if(int dpmac_id, int lane_prtc) +{ + return PHY_INTERFACE_MODE_NONE; +} + +void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl) +{ + phy_interface_t enet_if; + int index = dpmac_id + sd * 8; + + dpmac_info[index].enabled = 0; + dpmac_info[index].id = 0; + dpmac_info[index].enet_if = PHY_INTERFACE_MODE_NONE; + + enet_if = wriop_dpmac_enet_if(index, lane_prtcl); + if (enet_if != PHY_INTERFACE_MODE_NONE) { + dpmac_info[index].enabled = 1; + dpmac_info[index].id = index; + dpmac_info[index].enet_if = enet_if; + } +} + +/*TODO what it do */ +static int wriop_dpmac_to_index(int dpmac_id) +{ + int i; + + for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) { + if (dpmac_info[i].id == dpmac_id) + return i; + } + + return -1; +} + +void wriop_disable_dpmac(int dpmac_id) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return; + + dpmac_info[i].enabled = 0; + wriop_dpmac_disable(dpmac_id); +} + +void wriop_enable_dpmac(int dpmac_id) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return; + + dpmac_info[i].enabled = 1; + wriop_dpmac_enable(dpmac_id); +} + +void wriop_set_mdio(int dpmac_id, struct mii_dev *bus) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return; + + dpmac_info[i].bus = bus; +} + +struct mii_dev *wriop_get_mdio(int dpmac_id) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return NULL; + + return dpmac_info[i].bus; +} + +void wriop_set_phy_address(int dpmac_id, int address) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return; + + dpmac_info[i].phy_addr = address; +} + +int wriop_get_phy_address(int dpmac_id) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return -1; + + return dpmac_info[i].phy_addr; +} + +void wriop_set_phy_dev(int dpmac_id, struct phy_device *phydev) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return; + + dpmac_info[i].phydev = phydev; +} + +struct phy_device *wriop_get_phy_dev(int dpmac_id) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return NULL; + + return dpmac_info[i].phydev; +} + +phy_interface_t wriop_get_enet_if(int dpmac_id) +{ + int i = wriop_dpmac_to_index(dpmac_id); + + if (i == -1) + return PHY_INTERFACE_MODE_NONE; + + if (dpmac_info[i].enabled) + return dpmac_info[i].enet_if; + + return PHY_INTERFACE_MODE_NONE; +} diff --git a/drivers/net/ldpaa_eth/ls2085a.c b/drivers/net/ldpaa_eth/ls2085a.c new file mode 100644 index 0000000..6b7960a --- /dev/null +++ b/drivers/net/ldpaa_eth/ls2085a.c @@ -0,0 +1,83 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <phy.h> +#include <fsl-mc/ldpaa_wriop.h> +#include <asm/io.h> +#include <asm/arch-fsl-lsch3/immap_lsch3.h> +#include <asm/arch/fsl_serdes.h> +#include <fsl-mc/ldpaa_wriop.h> + +u32 dpmac_to_devdisr[] = { + [WRIOP1_DPMAC1] = FSL_CHASSIS3_DEVDISR2_DPMAC1, + [WRIOP1_DPMAC2] = FSL_CHASSIS3_DEVDISR2_DPMAC2, + [WRIOP1_DPMAC3] = FSL_CHASSIS3_DEVDISR2_DPMAC3, + [WRIOP1_DPMAC4] = FSL_CHASSIS3_DEVDISR2_DPMAC4, + [WRIOP1_DPMAC5] = FSL_CHASSIS3_DEVDISR2_DPMAC5, + [WRIOP1_DPMAC6] = FSL_CHASSIS3_DEVDISR2_DPMAC6, + [WRIOP1_DPMAC7] = FSL_CHASSIS3_DEVDISR2_DPMAC7, + [WRIOP1_DPMAC8] = FSL_CHASSIS3_DEVDISR2_DPMAC8, + [WRIOP1_DPMAC9] = FSL_CHASSIS3_DEVDISR2_DPMAC9, + [WRIOP1_DPMAC10] = FSL_CHASSIS3_DEVDISR2_DPMAC10, + [WRIOP1_DPMAC11] = FSL_CHASSIS3_DEVDISR2_DPMAC11, + [WRIOP1_DPMAC12] = FSL_CHASSIS3_DEVDISR2_DPMAC12, + [WRIOP1_DPMAC13] = FSL_CHASSIS3_DEVDISR2_DPMAC13, + [WRIOP1_DPMAC14] = FSL_CHASSIS3_DEVDISR2_DPMAC14, + [WRIOP1_DPMAC15] = FSL_CHASSIS3_DEVDISR2_DPMAC15, + [WRIOP1_DPMAC16] = FSL_CHASSIS3_DEVDISR2_DPMAC16, + [WRIOP1_DPMAC17] = FSL_CHASSIS3_DEVDISR2_DPMAC17, + [WRIOP1_DPMAC18] = FSL_CHASSIS3_DEVDISR2_DPMAC18, + [WRIOP1_DPMAC19] = FSL_CHASSIS3_DEVDISR2_DPMAC19, + [WRIOP1_DPMAC20] = FSL_CHASSIS3_DEVDISR2_DPMAC20, + [WRIOP1_DPMAC21] = FSL_CHASSIS3_DEVDISR2_DPMAC21, + [WRIOP1_DPMAC22] = FSL_CHASSIS3_DEVDISR2_DPMAC22, + [WRIOP1_DPMAC23] = FSL_CHASSIS3_DEVDISR2_DPMAC23, + [WRIOP1_DPMAC24] = FSL_CHASSIS3_DEVDISR2_DPMAC24, +}; + +static int is_device_disabled(int dpmac_id) +{ + struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; + u32 devdisr2 = in_le32(&gur->devdisr2); + + return dpmac_to_devdisr[dpmac_id] & devdisr2; +} + +void wriop_dpmac_disable(int dpmac_id) +{ + struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; + + setbits_le32(&gur->devdisr2, dpmac_to_devdisr[dpmac_id]); +} + +void wriop_dpmac_enable(int dpmac_id) +{ + struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; + + clrbits_le32(&gur->devdisr2, dpmac_to_devdisr[dpmac_id]); +} + +phy_interface_t wriop_dpmac_enet_if(int dpmac_id, int lane_prtcl) +{ + enum srds_prtcl; + + if (is_device_disabled(dpmac_id + 1)) + return PHY_INTERFACE_MODE_NONE; + + if (lane_prtcl >= SGMII1 && lane_prtcl <= SGMII16) + return PHY_INTERFACE_MODE_SGMII; + + if (lane_prtcl >= XFI1 && lane_prtcl <= XFI8) + return PHY_INTERFACE_MODE_XGMII; + + if (lane_prtcl >= XAUI1 && lane_prtcl <= XAUI2) + return PHY_INTERFACE_MODE_XGMII; + + if (lane_prtcl >= QSGMII_A && lane_prtcl <= QSGMII_D) + return PHY_INTERFACE_MODE_QSGMII; + + return PHY_INTERFACE_MODE_NONE; +} diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index 254f056..3a2b3bb 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -186,8 +186,8 @@ void cs4340_upload_firmware(struct phy_device *phydev) while (*addr != 0x0a) { line_temp[i++] = *addr++; if (0x50 < i) { - printf("Not found Cortina PHY ucode at 0x%x\n", - CONFIG_CORTINA_FW_ADDR); + printf("Not found Cortina PHY ucode at 0x%p\n", + (char *)CONFIG_CORTINA_FW_ADDR); return; } } diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c index 9fc3c18..fed7358 100644 --- a/drivers/net/vsc9953.c +++ b/drivers/net/vsc9953.c @@ -9,7 +9,7 @@ #include <asm/io.h> #include <asm/fsl_serdes.h> #include <fm_eth.h> -#include <asm/fsl_memac.h> +#include <fsl_memac.h> #include <vsc9953.h> static struct vsc9953_info vsc9953_l2sw = { diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index bcad8f2..402c519 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -11,7 +11,6 @@ #include <asm/io.h> #include <errno.h> #include <malloc.h> -#include <asm/pcie_layerscape.h> #ifndef CONFIG_SYS_PCI_MEMORY_BUS #define CONFIG_SYS_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE @@ -50,11 +49,20 @@ #define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) #define PCIE_ATU_UPPER_TARGET 0x91C +/* LUT registers */ +#define PCIE_LUT_BASE 0x80000 +#define PCIE_LUT_DBG 0x7FC + +#define PCIE_DBI_RO_WR_EN 0x8bc + #define PCIE_LINK_CAP 0x7c #define PCIE_LINK_SPEED_MASK 0xf #define PCIE_LINK_STA 0x82 -#define PCIE_DBI_SIZE (4 * 1024) /* 4K */ +#define LTSSM_STATE_MASK 0x3f +#define LTSSM_PCIE_L0 0x11 /* L0 state */ + +#define PCIE_DBI_SIZE 0x100000 /* 1M */ struct ls_pcie { int idx; @@ -104,8 +112,6 @@ struct ls_pcie_info { /* PEX1/2 Misc Ports Status Register */ #define LTSSM_STATE_SHIFT 20 -#define LTSSM_STATE_MASK 0x3f -#define LTSSM_PCIE_L0 0x11 /* L0 state */ static int ls_pcie_link_state(struct ls_pcie *pcie) { @@ -122,18 +128,18 @@ static int ls_pcie_link_state(struct ls_pcie *pcie) return 1; } #else -#define PCIE_LDBG 0x7FC - static int ls_pcie_link_state(struct ls_pcie *pcie) { u32 state; - state = readl(pcie->dbi + PCIE_LDBG); - if (state) - return 1; + state = readl(pcie->dbi + PCIE_LUT_BASE + PCIE_LUT_DBG) & + LTSSM_STATE_MASK; + if (state < LTSSM_PCIE_L0) { + debug("....PCIe link error. LTSSM=0x%02x.\n", state); + return 0; + } - debug("....PCIe link error.\n"); - return 0; + return 1; } #endif @@ -149,7 +155,11 @@ static int ls_pcie_link_up(struct ls_pcie *pcie) /* Try to download speed to gen1 */ cap = readl(pcie->dbi + PCIE_LINK_CAP); writel((cap & (~PCIE_LINK_SPEED_MASK)) | 1, pcie->dbi + PCIE_LINK_CAP); - udelay(2000); + /* + * Notice: the following delay has critical impact on link training + * if too short (<30ms) the link doesn't get up. + */ + mdelay(100); state = ls_pcie_link_state(pcie); if (state) return state; @@ -251,6 +261,10 @@ static int ls_pcie_addr_valid(struct pci_controller *hose, pci_dev_t d) if (PCI_DEV(d) > 0) return -EINVAL; + /* Controller does not support multi-function in RC mode */ + if ((PCI_BUS(d) == hose->first_busno) && (PCI_FUNC(d) > 0)) + return -EINVAL; + return 0; } @@ -327,8 +341,12 @@ static void ls_pcie_setup_ctrl(struct ls_pcie *pcie, pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0); /* program correct class for RC */ + writel(1, pcie->dbi + PCIE_DBI_RO_WR_EN); pci_hose_write_config_word(hose, dev, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); +#ifndef CONFIG_LS102XA + writel(0, pcie->dbi + PCIE_DBI_RO_WR_EN); +#endif } int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info) @@ -417,9 +435,9 @@ int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info) } /* Print the negotiated PCIe link width */ - pci_hose_read_config_word(hose, dev, PCIE_LINK_STA, &temp16); - printf("x%d gen%d, regs @ 0x%lx\n", (temp16 & 0x3f0) >> 4, - (temp16 & 0xf), info->regs); + pci_hose_read_config_word(hose, pdev, PCIE_LINK_STA, &temp16); + printf("x%d gen%d, regs @ 0x%lx\n", (temp16 & 0x3f0) >> 4, + (temp16 & 0xf), info->regs); if (ep_mode) return busno; @@ -486,7 +504,7 @@ static void ft_pcie_ls_setup(void *blob, const char *pci_compat, fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); } -void ft_pcie_setup(void *blob, bd_t *bd) +void ft_pci_setup(void *blob, bd_t *bd) { #ifdef CONFIG_PCIE1 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE1_ADDR, PCIE1); @@ -506,7 +524,7 @@ void ft_pcie_setup(void *blob, bd_t *bd) } #else -void ft_pcie_setup(void *blob, bd_t *bd) +void ft_pci_setup(void *blob, bd_t *bd) { } #endif diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index d24651b..84e1433 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -196,6 +196,18 @@ void u_qe_init(void) } #endif +#ifdef CONFIG_U_QE +void u_qe_resume(void) +{ + qe_map_t *qe_immrr; + uint qe_base = CONFIG_SYS_IMMR + QE_IMMR_OFFSET; /* QE immr base */ + qe_immrr = (qe_map_t *)qe_base; + + u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr); + out_be32(&qe_immrr->iram.iready, QE_IRAM_READY); +} +#endif + void qe_reset(void) { qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, @@ -580,6 +592,76 @@ int u_qe_upload_firmware(const struct qe_firmware *firmware) } #endif +#ifdef CONFIG_U_QE +int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr) +{ + unsigned int i; + unsigned int j; + const struct qe_header *hdr; + const u32 *code; +#ifdef CONFIG_DEEP_SLEEP +#ifdef CONFIG_PPC + ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +#else + struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; +#endif +#endif + + if (!firmware) + return -EINVAL; + + hdr = &firmware->header; + + /* Check the magic */ + if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || + (hdr->magic[2] != 'F')) { +#ifdef CONFIG_DEEP_SLEEP + setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); +#endif + return -EPERM; + } + + /* + * If the microcode calls for it, split the I-RAM. + */ + if (!firmware->split) { + out_be16(&qe_immrr->cp.cercr, + in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR); + } + + /* Loop through each microcode. */ + for (i = 0; i < firmware->count; i++) { + const struct qe_microcode *ucode = &firmware->microcode[i]; + + /* Upload a microcode if it's present */ + if (!ucode->code_offset) + return 0; + + code = (const void *)firmware + be32_to_cpu(ucode->code_offset); + + /* Use auto-increment */ + out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) | + QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); + + for (i = 0; i < be32_to_cpu(ucode->count); i++) + out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i])); + + /* Program the traps for this processor */ + for (j = 0; j < 16; j++) { + u32 trap = be32_to_cpu(ucode->traps[j]); + + if (trap) + out_be32(&qe_immrr->rsp[i].tibcr[j], trap); + } + + /* Enable traps */ + out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); + } + + return 0; +} +#endif + struct qe_firmware_info *qe_get_firmware_info(void) { return qe_firmware_uploaded ? &qe_firmware_info : NULL; diff --git a/drivers/qe/qe.h b/drivers/qe/qe.h index 33878f8..77b18e9 100644 --- a/drivers/qe/qe.h +++ b/drivers/qe/qe.h @@ -11,6 +11,9 @@ #define __QE_H__ #include "common.h" +#ifdef CONFIG_U_QE +#include <linux/immap_qe.h> +#endif #define QE_NUM_OF_BRGS 16 #define UCC_MAX_NUM 8 @@ -288,6 +291,9 @@ void qe_reset(void); #ifdef CONFIG_U_QE void u_qe_init(void); int u_qe_upload_firmware(const struct qe_firmware *firmware); +void u_qe_resume(void); +int u_qe_firmware_resume(const struct qe_firmware *firmware, + qe_map_t *qe_immrr); #endif #endif /* __QE_H__ */ diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 5d4288d..2dca524 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -259,10 +259,11 @@ static int fdt_fixup_usb_erratum(void *blob, const char *prop_erratum, void fdt_fixup_dr_usb(void *blob, bd_t *bd) { static const char * const modes[] = { "host", "peripheral", "otg" }; - static const char * const phys[] = { "ulpi", "utmi" }; + static const char * const phys[] = { "ulpi", "utmi", "utmi_dual" }; int usb_erratum_a006261_off = -1; int usb_erratum_a007075_off = -1; int usb_erratum_a007792_off = -1; + int usb_erratum_a005697_off = -1; int usb_mode_off = -1; int usb_phy_off = -1; char str[5]; @@ -303,6 +304,9 @@ void fdt_fixup_dr_usb(void *blob, bd_t *bd) dr_phy_type = phys[phy_idx]; } + if (has_dual_phy()) + dr_phy_type = phys[2]; + usb_mode_off = fdt_fixup_usb_mode_phy_type(blob, dr_mode_type, NULL, usb_mode_off); @@ -325,6 +329,7 @@ void fdt_fixup_dr_usb(void *blob, bd_t *bd) if (usb_erratum_a006261_off < 0) return; } + if (has_erratum_a007075()) { usb_erratum_a007075_off = fdt_fixup_usb_erratum (blob, @@ -333,6 +338,7 @@ void fdt_fixup_dr_usb(void *blob, bd_t *bd) if (usb_erratum_a007075_off < 0) return; } + if (has_erratum_a007792()) { usb_erratum_a007792_off = fdt_fixup_usb_erratum (blob, @@ -341,6 +347,14 @@ void fdt_fixup_dr_usb(void *blob, bd_t *bd) if (usb_erratum_a007792_off < 0) return; } + if (has_erratum_a005697()) { + usb_erratum_a005697_off = fdt_fixup_usb_erratum + (blob, + "fsl,usb-erratum-a005697", + usb_erratum_a005697_off); + if (usb_erratum_a005697_off < 0) + return; + } } } #endif |