mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
drivers: mmc: export SD extension register read/write functions
Certain status bits in these registers may need polling outside of SD-specific code. Export in sd_ops.h Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
This commit is contained in:
committed by
Dom Cobley
parent
f9c83a2bf6
commit
168c57a685
@@ -1034,83 +1034,6 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
|
|||||||
(SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
|
(SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
|
|
||||||
u8 reg_data)
|
|
||||||
{
|
|
||||||
struct mmc_host *host = card->host;
|
|
||||||
struct mmc_request mrq = {};
|
|
||||||
struct mmc_command cmd = {};
|
|
||||||
struct mmc_data data = {};
|
|
||||||
struct scatterlist sg;
|
|
||||||
u8 *reg_buf;
|
|
||||||
|
|
||||||
reg_buf = card->ext_reg_buf;
|
|
||||||
memset(reg_buf, 0, 512);
|
|
||||||
|
|
||||||
mrq.cmd = &cmd;
|
|
||||||
mrq.data = &data;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Arguments of CMD49:
|
|
||||||
* [31:31] MIO (0 = memory).
|
|
||||||
* [30:27] FNO (function number).
|
|
||||||
* [26:26] MW - mask write mode (0 = disable).
|
|
||||||
* [25:18] page number.
|
|
||||||
* [17:9] offset address.
|
|
||||||
* [8:0] length (0 = 1 byte).
|
|
||||||
*/
|
|
||||||
cmd.arg = fno << 27 | page << 18 | offset << 9;
|
|
||||||
|
|
||||||
/* The first byte in the buffer is the data to be written. */
|
|
||||||
reg_buf[0] = reg_data;
|
|
||||||
|
|
||||||
data.flags = MMC_DATA_WRITE;
|
|
||||||
data.blksz = 512;
|
|
||||||
data.blocks = 1;
|
|
||||||
data.sg = &sg;
|
|
||||||
data.sg_len = 1;
|
|
||||||
sg_init_one(&sg, reg_buf, 512);
|
|
||||||
|
|
||||||
cmd.opcode = SD_WRITE_EXTR_SINGLE;
|
|
||||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
|
||||||
|
|
||||||
mmc_set_data_timeout(&data, card);
|
|
||||||
mmc_wait_for_req(host, &mrq);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that, the SD card is allowed to signal busy on DAT0 up to 1s
|
|
||||||
* after the CMD49. Although, let's leave this to be managed by the
|
|
||||||
* caller.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (cmd.error)
|
|
||||||
return cmd.error;
|
|
||||||
if (data.error)
|
|
||||||
return data.error;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
|
|
||||||
u16 offset, u16 len, u8 *reg_buf)
|
|
||||||
{
|
|
||||||
u32 cmd_args;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command arguments of CMD48:
|
|
||||||
* [31:31] MIO (0 = memory).
|
|
||||||
* [30:27] FNO (function number).
|
|
||||||
* [26:26] reserved (0).
|
|
||||||
* [25:18] page number.
|
|
||||||
* [17:9] offset address.
|
|
||||||
* [8:0] length (0 = 1 byte, 1ff = 512 bytes).
|
|
||||||
*/
|
|
||||||
cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
|
|
||||||
|
|
||||||
return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
|
|
||||||
cmd_args, reg_buf, 512);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
|
static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
|
||||||
u16 offset)
|
u16 offset)
|
||||||
{
|
{
|
||||||
@@ -1120,7 +1043,7 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
|
|||||||
reg_buf = card->ext_reg_buf;
|
reg_buf = card->ext_reg_buf;
|
||||||
|
|
||||||
/* Read the extension register for power management function. */
|
/* Read the extension register for power management function. */
|
||||||
err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
|
err = mmc_sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("%s: error %d reading PM func of ext reg\n",
|
pr_warn("%s: error %d reading PM func of ext reg\n",
|
||||||
mmc_hostname(card->host), err);
|
mmc_hostname(card->host), err);
|
||||||
@@ -1158,7 +1081,7 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
|
|||||||
|
|
||||||
reg_buf = card->ext_reg_buf;
|
reg_buf = card->ext_reg_buf;
|
||||||
|
|
||||||
err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
|
err = mmc_sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("%s: error %d reading PERF func of ext reg\n",
|
pr_warn("%s: error %d reading PERF func of ext reg\n",
|
||||||
mmc_hostname(card->host), err);
|
mmc_hostname(card->host), err);
|
||||||
@@ -1253,7 +1176,7 @@ static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sd_read_ext_regs(struct mmc_card *card)
|
static int mmc_sd_read_ext_regs(struct mmc_card *card)
|
||||||
{
|
{
|
||||||
int err, i;
|
int err, i;
|
||||||
u8 num_ext, *gen_info_buf;
|
u8 num_ext, *gen_info_buf;
|
||||||
@@ -1279,7 +1202,7 @@ static int sd_read_ext_regs(struct mmc_card *card)
|
|||||||
* Read 512 bytes of general info, which is found at function number 0,
|
* Read 512 bytes of general info, which is found at function number 0,
|
||||||
* at page 0 and with no offset.
|
* at page 0 and with no offset.
|
||||||
*/
|
*/
|
||||||
err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
|
err = mmc_sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("%s: error %d reading general info of SD ext reg\n",
|
pr_err("%s: error %d reading general info of SD ext reg\n",
|
||||||
mmc_hostname(card->host), err);
|
mmc_hostname(card->host), err);
|
||||||
@@ -1351,7 +1274,7 @@ static int sd_flush_cache(struct mmc_host *host)
|
|||||||
page = card->ext_perf.page;
|
page = card->ext_perf.page;
|
||||||
offset = card->ext_perf.offset + 261;
|
offset = card->ext_perf.offset + 261;
|
||||||
|
|
||||||
err = sd_write_ext_reg(card, fno, page, offset, BIT(0));
|
err = mmc_sd_write_ext_reg(card, fno, page, offset, BIT(0));
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("%s: error %d writing Cache Flush bit\n",
|
pr_warn("%s: error %d writing Cache Flush bit\n",
|
||||||
mmc_hostname(host), err);
|
mmc_hostname(host), err);
|
||||||
@@ -1367,7 +1290,7 @@ static int sd_flush_cache(struct mmc_host *host)
|
|||||||
* Read the Flush Cache bit. The card shall reset it, to confirm that
|
* Read the Flush Cache bit. The card shall reset it, to confirm that
|
||||||
* it's has completed the flushing of the cache.
|
* it's has completed the flushing of the cache.
|
||||||
*/
|
*/
|
||||||
err = sd_read_ext_reg(card, fno, page, offset, 1, reg_buf);
|
err = mmc_sd_read_ext_reg(card, fno, page, offset, 1, reg_buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("%s: error %d reading Cache Flush bit\n",
|
pr_warn("%s: error %d reading Cache Flush bit\n",
|
||||||
mmc_hostname(host), err);
|
mmc_hostname(host), err);
|
||||||
@@ -1390,7 +1313,7 @@ static int sd_enable_cache(struct mmc_card *card)
|
|||||||
* Set Cache Enable at bit 0 in the performance enhancement register at
|
* Set Cache Enable at bit 0 in the performance enhancement register at
|
||||||
* 260 bytes offset.
|
* 260 bytes offset.
|
||||||
*/
|
*/
|
||||||
err = sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
|
err = mmc_sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
|
||||||
card->ext_perf.offset + 260, BIT(0));
|
card->ext_perf.offset + 260, BIT(0));
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("%s: error %d writing Cache Enable bit\n",
|
pr_warn("%s: error %d writing Cache Enable bit\n",
|
||||||
@@ -1566,7 +1489,7 @@ retry:
|
|||||||
cont:
|
cont:
|
||||||
if (!oldcard) {
|
if (!oldcard) {
|
||||||
/* Read/parse the extension registers. */
|
/* Read/parse the extension registers. */
|
||||||
err = sd_read_ext_regs(card);
|
err = mmc_sd_read_ext_regs(card);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_card;
|
goto free_card;
|
||||||
}
|
}
|
||||||
@@ -1685,7 +1608,7 @@ static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
|
|||||||
* one byte offset and is one byte long. The Power Off Notification
|
* one byte offset and is one byte long. The Power Off Notification
|
||||||
* Ready is bit 0.
|
* Ready is bit 0.
|
||||||
*/
|
*/
|
||||||
err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
|
err = mmc_sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
|
||||||
card->ext_power.offset + 1, 1, data->reg_buf);
|
card->ext_power.offset + 1, 1, data->reg_buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("%s: error %d reading status reg of PM func\n",
|
pr_warn("%s: error %d reading status reg of PM func\n",
|
||||||
@@ -1711,7 +1634,7 @@ static int sd_poweroff_notify(struct mmc_card *card)
|
|||||||
* Set the Power Off Notification bit in the power management settings
|
* Set the Power Off Notification bit in the power management settings
|
||||||
* register at 2 bytes offset.
|
* register at 2 bytes offset.
|
||||||
*/
|
*/
|
||||||
err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
|
err = mmc_sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
|
||||||
card->ext_power.offset + 2, BIT(0));
|
card->ext_power.offset + 2, BIT(0));
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("%s: error %d writing Power Off Notify bit\n",
|
pr_warn("%s: error %d writing Power Off Notify bit\n",
|
||||||
|
|||||||
@@ -418,8 +418,83 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
|
|
||||||
u8 reg_data);
|
int mmc_sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
|
||||||
|
u8 reg_data)
|
||||||
|
{
|
||||||
|
struct mmc_host *host = card->host;
|
||||||
|
struct mmc_request mrq = {};
|
||||||
|
struct mmc_command cmd = {};
|
||||||
|
struct mmc_data data = {};
|
||||||
|
struct scatterlist sg;
|
||||||
|
u8 *reg_buf;
|
||||||
|
|
||||||
|
reg_buf = card->ext_reg_buf;
|
||||||
|
memset(reg_buf, 0, 512);
|
||||||
|
|
||||||
|
mrq.cmd = &cmd;
|
||||||
|
mrq.data = &data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arguments of CMD49:
|
||||||
|
* [31:31] MIO (0 = memory).
|
||||||
|
* [30:27] FNO (function number).
|
||||||
|
* [26:26] MW - mask write mode (0 = disable).
|
||||||
|
* [25:18] page number.
|
||||||
|
* [17:9] offset address.
|
||||||
|
* [8:0] length (0 = 1 byte).
|
||||||
|
*/
|
||||||
|
cmd.arg = fno << 27 | page << 18 | offset << 9;
|
||||||
|
|
||||||
|
/* The first byte in the buffer is the data to be written. */
|
||||||
|
reg_buf[0] = reg_data;
|
||||||
|
|
||||||
|
data.flags = MMC_DATA_WRITE;
|
||||||
|
data.blksz = 512;
|
||||||
|
data.blocks = 1;
|
||||||
|
data.sg = &sg;
|
||||||
|
data.sg_len = 1;
|
||||||
|
sg_init_one(&sg, reg_buf, 512);
|
||||||
|
|
||||||
|
cmd.opcode = SD_WRITE_EXTR_SINGLE;
|
||||||
|
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||||
|
|
||||||
|
mmc_set_data_timeout(&data, card);
|
||||||
|
mmc_wait_for_req(host, &mrq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that, the SD card is allowed to signal busy on DAT0 up to 1s
|
||||||
|
* after the CMD49. Although, let's leave this to be managed by the
|
||||||
|
* caller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cmd.error)
|
||||||
|
return cmd.error;
|
||||||
|
if (data.error)
|
||||||
|
return data.error;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mmc_sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
|
||||||
|
u16 offset, u16 len, u8 *reg_buf)
|
||||||
|
{
|
||||||
|
u32 cmd_args;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command arguments of CMD48:
|
||||||
|
* [31:31] MIO (0 = memory).
|
||||||
|
* [30:27] FNO (function number).
|
||||||
|
* [26:26] reserved (0).
|
||||||
|
* [25:18] page number.
|
||||||
|
* [17:9] offset address.
|
||||||
|
* [8:0] length (0 = 1 byte, 1ff = 512 bytes).
|
||||||
|
*/
|
||||||
|
cmd_args = fno << 27 | page << 18 | offset << 9 | (len - 1);
|
||||||
|
|
||||||
|
return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
|
||||||
|
cmd_args, reg_buf, 512);
|
||||||
|
}
|
||||||
|
|
||||||
static int mmc_sd_cmdq_switch(struct mmc_card *card, bool enable)
|
static int mmc_sd_cmdq_switch(struct mmc_card *card, bool enable)
|
||||||
{
|
{
|
||||||
@@ -435,8 +510,8 @@ static int mmc_sd_cmdq_switch(struct mmc_card *card, bool enable)
|
|||||||
reg = BIT(0);
|
reg = BIT(0);
|
||||||
|
|
||||||
/* Performance enhancement register byte 262 controls command queueing */
|
/* Performance enhancement register byte 262 controls command queueing */
|
||||||
err = sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
|
err = mmc_sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
|
||||||
card->ext_perf.offset + 262, reg);
|
card->ext_perf.offset + 262, reg);
|
||||||
if (!err)
|
if (!err)
|
||||||
card->ext_csd.cmdq_en = enable;
|
card->ext_csd.cmdq_en = enable;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ int mmc_send_ext_addr(struct mmc_host *host, u32 addr);
|
|||||||
void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
|
void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
|
||||||
int mmc_sd_cmdq_enable(struct mmc_card *card);
|
int mmc_sd_cmdq_enable(struct mmc_card *card);
|
||||||
int mmc_sd_cmdq_disable(struct mmc_card *card);
|
int mmc_sd_cmdq_disable(struct mmc_card *card);
|
||||||
|
int mmc_sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
|
||||||
|
u8 reg_data);
|
||||||
|
int mmc_sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
|
||||||
|
u16 offset, u16 len, u8 *reg_buf);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user