sdram: Add MR read request

This commit is contained in:
CTCaer 2020-04-30 03:27:39 +03:00
parent 8c762c52e2
commit ecb616e411
6 changed files with 158 additions and 3 deletions

View file

@ -2,6 +2,7 @@
* arch/arm/mach-tegra/tegra21_emc.h
*
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019-2020, CTCaer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -664,4 +665,28 @@
#define EMC_PMC_SCRATCH2 0x444
#define EMC_PMC_SCRATCH3 0x448
#define EMC_STATUS_UPDATE_TIMEOUT 1000
typedef enum _emc_mr_t
{
MR5_MAN_ID = 5,
MR6_REV_ID1 = 6,
MR7_REV_ID2 = 7,
MR8_DENSITY = 8,
} emc_mr_t;
enum
{
EMC_CHAN0 = 0,
EMC_CHAN1 = 1
};
typedef struct _emc_mr_data_t
{
u8 dev0_ch0;
u8 dev0_ch1;
u8 dev1_ch0;
u8 dev1_ch1;
} emc_mr_data_t;
#endif

View file

@ -49,6 +49,56 @@ static u32 _get_sdram_id()
return sdram_id;
}
static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel)
{
bool err = true;
for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)
{
if (emc_channel)
{
if (emc_channel != 1)
goto done;
if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)
{
err = false;
break;
}
}
else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)
{
err = false;
break;
}
usleep(1);
}
done:
return err;
}
static void _sdram_req_mrr_data(u32 data, bool dual_channel)
{
EMC(EMC_MRR) = data;
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0);
if (dual_channel)
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1);
}
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
{
emc_mr_data_t data;
_sdram_req_mrr_data((1 << 31) | (mrx << 16), EMC_CHAN0);
data.dev0_ch0 = EMC(EMC_MRR) & 0xFF;
data.dev0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
_sdram_req_mrr_data((1 << 30) | (mrx << 16), EMC_CHAN1);
data.dev1_ch0 = EMC(EMC_MRR) & 0xFF;
data.dev1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
return data;
}
static void _sdram_config(const sdram_params_t *params)
{
// Program DPD3/DPD4 regs (coldboot path).
@ -91,7 +141,7 @@ break_nosleep:
if (params->emc_clock_source_dll)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
if (params->clear_clock2_mc1)
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.

View file

@ -17,11 +17,13 @@
#ifndef _SDRAM_H_
#define _SDRAM_H_
#include "emc.h"
#include "sdram_param_t210.h"
void sdram_init();
sdram_params_t *sdram_get_params();
sdram_params_t *sdram_get_params_patched();
void sdram_lp0_save_params(const void *params);
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
#endif

View file

@ -2,6 +2,7 @@
* arch/arm/mach-tegra/tegra21_emc.h
*
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019-2020, CTCaer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -231,6 +232,7 @@
#define EMC_COMP_PAD_SW_CTRL 0x57c
#define EMC_REQ_CTRL 0x2b0
#define EMC_EMC_STATUS 0x2b4
#define EMC_STATUS_MRR_DIVLD (1 << 20)
#define EMC_CFG_2 0x2b8
#define EMC_CFG_DIG_DLL 0x2bc
#define EMC_CFG_DIG_DLL_PERIOD 0x2c0
@ -664,4 +666,28 @@
#define EMC_PMC_SCRATCH2 0x444
#define EMC_PMC_SCRATCH3 0x448
#define EMC_STATUS_UPDATE_TIMEOUT 1000
typedef enum _emc_mr_t
{
MR5_MAN_ID = 5,
MR6_REV_ID1 = 6,
MR7_REV_ID2 = 7,
MR8_DENSITY = 8,
} emc_mr_t;
enum
{
EMC_CHAN0 = 0,
EMC_CHAN1 = 1
};
typedef struct _emc_mr_data_t
{
u8 dev0_ch0;
u8 dev0_ch1;
u8 dev1_ch0;
u8 dev1_ch1;
} emc_mr_data_t;
#endif

View file

@ -40,7 +40,57 @@
static u32 _get_sdram_id()
{
return (fuse_read_odm(4) & 0x38) >> 3;
return ((fuse_read_odm(4) & 0x38) >> 3);
}
static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel)
{
bool err = true;
for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)
{
if (emc_channel)
{
if (emc_channel != 1)
goto done;
if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)
{
err = false;
break;
}
}
else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)
{
err = false;
break;
}
usleep(1);
}
done:
return err;
}
static void _sdram_req_mrr_data(u32 data, bool dual_channel)
{
EMC(EMC_MRR) = data;
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0);
if (dual_channel)
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1);
}
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
{
emc_mr_data_t data;
_sdram_req_mrr_data((1 << 31) | (mrx << 16), EMC_CHAN0);
data.dev0_ch0 = EMC(EMC_MRR) & 0xFF;
data.dev0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
_sdram_req_mrr_data((1 << 30) | (mrx << 16), EMC_CHAN1);
data.dev1_ch0 = EMC(EMC_MRR) & 0xFF;
data.dev1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
return data;
}
static void _sdram_config(const sdram_params_t *params)
@ -85,7 +135,7 @@ break_nosleep:
if (params->emc_clock_source_dll)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
if (params->clear_clock2_mc1)
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.

View file

@ -17,11 +17,13 @@
#ifndef _SDRAM_H_
#define _SDRAM_H_
#include "emc.h"
#include "sdram_param_t210.h"
void sdram_init();
sdram_params_t *sdram_get_params();
sdram_params_t *sdram_get_params_patched();
void sdram_lp0_save_params(const void *params);
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
#endif