Decoding of embedded Linux driver--MMC/SD subsystem based on s3c2440 (i.) __linux

Source: Internet
Author: User
Tags data structures goto bit definition

Before reading this article, please master the following basics, or skip this article.

Preliminary Knowledge :

Read the first 10 chapters of LDD3.

Familiar with kernel-driven model (SYSFS) and platform bus.

Briefly understand the SD card specifications.


The content of this article is based on the following hardware and software platforms:

Target platform: TQ2440

cpu:s3c2440

Kernel version: 3.12.5

Based on SD specification 4.10, namely "SD specifications Part 1 Physical Layer simplified specification Version 4.10". I. MMC subsystem architecture

Waiting to write ...
ii. main Data Structures

Waiting to write ...
Third, MMC subsystem initialization

First look at how the subsystem is initialized and what is done.

The code is located in Linux/drivers/mmc/core/core.c.

static int __init mmc_init (void)
{
    int ret;

    /* Create a Task Force column * *
    workqueue = alloc_ordered_workqueue ("Kmmcd", 0);
    if (!workqueue)
        Return-enomem;

    /* Registers the MMC bus, the bus provides the probe method
       and directly calls in the internal drive probe method * *
    ret = Mmc_register_bus ();
    if (ret)
        goto destroy_workqueue;
    
    /* Register a class called Mmc_host
    /ret = Mmc_register_host_class ();
    if (ret)
        goto Unregister_bus;

    /* Registers the SDIO bus, the bus provides the probe method
       and directly calls the drive probe method in the internal call
    /ret = Sdio_register_bus ();
    if (ret)
        goto Unregister_host_class;

    return 0;

Unregister_host_class:
    mmc_unregister_host_class ();
Unregister_bus:
    Mmc_unregister_bus ();
Destroy_workqueue:
    destroy_workqueue (workqueue);

    return ret;
}

The Code first registers a task force column that will be used to scan the SD card device. We'll explain it later.

Work is running on the form of a kernel thread of a class, and you can see a kernel thread named [KMMCD] with the PS command.

It then registers two buses named MMC and Sdio, and a class named Mmc_host. The specific code is as follows:

static struct Bus_type Mmc_bus_type = {
	. Name		= "mmc",
	. Dev_attrs	= Mmc_dev_attrs,
	. Match		= Mmc_bus_match,
	. uevent		= mmc_bus_uevent,
	. Probe		= Mmc_bus_probe,
	. Remove		= Mmc_bus_ Remove,
	. Shutdown	= mmc_bus_shutdown,
	. PM		= &mmc_bus_pm_ops,
};

int Mmc_register_bus (void)
{return
	bus_register (&mmc_bus_type);
}

static struct Class Mmc_host_class = {
    . Name        = "Mmc_host",
    . Dev_release    = mmc_host_classdev_ Release,
};

int Mmc_register_host_class (void)
{return
    class_register (&mmc_host_class);
}

static struct Bus_type Sdio_bus_type = {
    . Name        = "Sdio",
    . Dev_attrs    = Sdio_dev_attrs,
    . Match        = Sdio_bus_match,
    . uevent        = sdio_bus_uevent,
    . Probe        = Sdio_bus_probe,
    . Remove        = Sdio_bus _remove,
    . PM        = sdio_pm_ops_ptr,
};

int Sdio_register_bus (void)
{return
    bus_register (&sdio_bus_type);
}

static struct Class Mmc_host_class = {
    . Name        = "Mmc_host",
    . Dev_release    = mmc_host_classdev_ Release,
};

int Mmc_register_host_class (void)
{return
    class_register (&mmc_host_class);
}

Students familiar with Linux's device-driven model must be familiar with these. The bus and class registrations simply invoke the corresponding interface, which is no longer discussed.

Secondly, the Sdio bus is not our concern. We only care about the MMC bus. First look at the match method for the MMC bus:

The code is located in LINUX/DRIVERS/MMC/CORE/BUS.C.

 * * This currently matches any MMC driver to any MMC card-drivers
 * themselves make the decision whether to DRI ve this card in their
 * Probe method.
 *
/static int mmc_bus_match (struct device *dev, struct device_driver *drv)
{return
	1;
}

Match returned with a direct return of 1. This means that any driver can match an MMC card device successfully.

As we can see from the annotations, the driven probe method will determine whether the driver can really match this MMC card device.

Familiar with the device-driven model, it is possible to know that the probe method provided by the bus will be invoked as match returns 1 to indicate a successful match. Next we look at the probe method of the MMC bus.

The code is located in LINUX/DRIVERS/MMC/CORE/BUS.C.

static int mmc_bus_probe (struct device *dev) {struct Mmc_driver *drv
	= To_mmc_driver (dev->driver);
	struct Mmc_card *card = Mmc_dev_to_card (dev);

	return Drv->probe (card);
From here we can see that the driver probe method is directly invoked in the probe method of MMC, which also validates what is said in the comments just now.

As you can see from the above analysis, subsystem initialization code registers only two buses and a class, and establishes a task queue.


interface API between core layer and controller layer

MMC core layer and SD card device to communicate, in order to complete this work needs to be cmd or ACMD command through the MMC/SD controller sent to the SD card.

Then how does the MMC core layer send the traffic packets to the MMC/SD controller and let the latter go?

MMC completes this work through function mmc_wait_for_req, let's take a look at this function. 4.1 mmc_wait_for_req function
The following code is located in Linux/drivers/mmc/core/core.c.

/**
 *	Mmc_wait_for_req-start a request and completion
 *	@host: MMC host to start command
 *<  c6/> @mrq: MMC request to start
 *	start a new MMC custom command request for a host, and	The command to complete. Does not attempt to parse the
 *	response.
 *
/void Mmc_wait_for_req (struct mmc_host *host, struct mmc_request *mrq)
{
	__mmc_start_req (host, MRQ);
	Mmc_wait_for_req_done (host, MRQ);
Export_symbol (Mmc_wait_for_req);

Annotations show that the function blocks and waits for the request to complete.

This function is divided into two steps, the first step calls __mmc_start_req to send the command, the second call Mmc_wait_for_req_done wait for the command to complete.

Look at the two functions separately:


static int __mmc_start_req (struct mmc_host *host, struct mmc_request *mrq)
{/
	* Initialize completion and set the Done method * *
	Init_completion (&mrq->completion);
	Mrq->done = Mmc_wait_done;
	/* If MMC has been unplugged, set error and return error *
	/if (mmc_card_removed (Host->card)) {
		mrq->cmd->error =-enomedium;
		Complete (&mrq->completion);
		Return-enomedium;
	}
	/* Send command
	/mmc_start_request (host, MRQ);
	return 0;
} 

The function first initializes the completion and sets the Mrq->done method to the Mmc_wait_done function, which is as follows.

static void Mmc_wait_done (struct mmc_request *mrq)
{
    complete (&mrq->completion);
}
The purpose of using completion here is to wait for the request to be sent to completion.

The Wait_for_completion function is used in the second step Mmc_wait_for_req_done to wait for the MMC controller to complete the request, and the controller driver will call the mrq-> when the request is completed. The done method activates the Wait_for_completion function that is in wait.

Then the function will first check whether the SD card has been unplugged, if the card has been unplugged is not necessary to send request, you can directly call the Copletion function of the related wait function, set the error value and then return an error.

#define MMC_CARD_REMOVED (c)	((c) && ((c)->state & mmc_card_removed))

If the SD card exists, call the Mmc_start_request function to send the request, which is as follows:

static void Mmc_start_request (struct mmc_host *host, struct mmc_request *mrq) {#ifdef config_mmc_debug unsigned int i
    , Sz;
struct Scatterlist *sg; #endif if (MRQ-&GT;SBC) {pr_debug ("<%s:starting cmd%u arg%08x flags%08x>\n", MMC_HOSTN
    Ame (host), Mrq->sbc->opcode, Mrq->sbc->arg, mrq->sbc->flags);
         } pr_debug ("%s:starting cmd%u arg%08x flags%08x\n", Mmc_hostname (host), Mrq->cmd->opcode,

    Mrq->cmd->arg, Mrq->cmd->flags);
            if (mrq->data) {pr_debug ("%s:blksz%d blocks%d flags%08x" "Tsac%d ms Nsac%d\n", Mmc_hostname (host), Mrq->data->blksz, Mrq->data->blocks, Mrq->data->flags, M
    rq->data->timeout_ns/1000000, mrq->data->timeout_clks); } if (mrq->stop) {pr_debug ("%s:cmd%u arg%08x flags%08x\n", Mmc_hostname (host), MRQ-&G T; Stop->opcode, Mrq->stop->arg, mrq->stop->flags);

    } warn_on (!host->claimed);
    Mrq->cmd->error = 0;
    MRQ-&GT;CMD-&GT;MRQ = MRQ;
        if (mrq->data) {bug_on (Mrq->data->blksz > Host->max_blk_size);
        bug_on (Mrq->data->blocks > Host->max_blk_count);

BUG_ON (mrq->data->blocks * mrq->data->blksz > Host->max_req_size);
        #ifdef config_mmc_debug sz = 0;
        FOR_EACH_SG (MRQ-&GT;DATA-&GT;SG, SG, Mrq->data->sg_len, i) sz + + sg->length;
bug_on (sz!= mrq->data->blocks * Mrq->data->blksz);
        #endif mrq->cmd->data = mrq->data;
        Mrq->data->error = 0;
        MRQ-&GT;DATA-&GT;MRQ = MRQ;
            if (mrq->stop) {mrq->data->stop = mrq->stop;
            Mrq->stop->error = 0;
        MRQ-&GT;STOP-&GT;MRQ = MRQ;
    } mmc_host_clk_hold (host); Led_Trigger_event (host->led, led_full);
/* Send request*/host->ops->request (host, MRQ); }
The function prints a bunch of information and then clears the cmd->error and binds cmd and MRQ, and then if MRQ is requesting data

Mmc_host_clk_hold function is through the macro config_mmc_clkgate to enable, the macro default is not open, the specific does not analyze, briefly on the role of the macro.

The function of this macro is to enable clock gating, which stops the MMC controller when the MMC controller is not needed to save power.

Then will invoke the Led_trigger_event trigger event, this involves the LED subsystem, will not be explained.

Incidentally, the S3C2440 MMC controller driver does not use this led triggering feature, which means that the host->led is empty.

Finally, the request method provided by the MMC controller driver is invoked to send the request.

Here you need to take note of the parameters of the function pointer: one for host to represent an MMC controller, and one for MRQ to represent the request.

Obviously, the host-directed MMC controller is required to send a MRQ-pointing request, and it can be seen that all requests passed to the MMC controller driver are encapsulated using the struct mmc_request structure.

So the first step is done, and then we look at step two:

static void Mmc_wait_for_req_done (struct mmc_host *host, struct mmc_request *mrq) {struct Mmc_command;

		while (1) {wait_for_completion (&mrq->completion);

		cmd = mrq->cmd; /* If host has timed out waiting for the sanitize * to complete, card might is still in programming
		 Let's try to bring the "card out of" programming * state. */if (cmd->sanitize_busy && cmd->error = =-etimedout) {if (!mmc_interrupt_hpi (Host->card)) {p
				R_warning ("%s:%s:interrupted sanitize\n", Mmc_hostname (host), __func__);
				Cmd->error = 0;
			Break
			else {Pr_err ("%s:%s:failed to interrupt sanitize\n", Mmc_hostname (host), __func__);
		    } if (!cmd->error | |!cmd->retries | |

		Mmc_card_removed (Host->card)) break;
		Pr_debug ("%s:req failed (cmd%u):%d, retrying...\n", Mmc_hostname (host), Cmd->opcode, Cmd->error);
		cmd->retries--;
          Cmd->error = 0;      /* No success, try to send request*/  host->ops->request (host, MRQ) again;
 }
}
This function first invokes wait_for_completion to wait for the MMC controller driver to invoke Mmc_wait_done to wake itself up.

After being awakened, a series of checks are performed, and if the request is sent successfully, it will break and return directly.

If it is not sent successfully, as long as retries is not 0, you will try to invoke the MMC controller-driven request method again to send. 4.2 cmd and acmd send functions

With the 4.1 Summary, we know how the MMC core layer will give the request to the MMC controller, and the latter to send the request to the SD card.

Through the SD card specification, we know that there are two forms of command, one for CMD, and the other for ACMD.

The MMC subsystem provides two functions for sending these two commands, Mmc_wait_for_cmd and Mmc_wait_for_app_cmd respectively.

Let's take a look at the sending function of cmd:

The following code is located in Linux/drivers/mmc/core/core.c.

/**
 *	mmc_wait_for_cmd-start a command and wait for completion
 *	@host: MMC host to start command
 *< c5/> @cmd: MMC command to start
 *	@retries: Maximum number of retries
 *
 *	start a new MMC command for A host, and wait for the command
 * to	complete.  Return any error this occurred while the command
 * is	executing.  Don't attempt to parse the response.
 * *
int mmc_wait_for_cmd (struct mmc_host *host, struct mmc_command *cmd, int retries)
{
	struct MMC_ Request MRQ = {NULL};

	WARN_ON (!host->claimed);

	/* Empty Answer * *
	memset (cmd->resp, 0, sizeof (CMD->RESP));
	Cmd->retries = retries;

	/* Save command *
	/mrq.cmd = cmd;
	Cmd->data = NULL;

	/* Send command and wait for response * *
	mmc_wait_for_req (host, &MRQ);

	Return cmd->error;
}
With the analysis of 4.1 summary, this function is relatively simple.

The function first empties the command's answer data (RESP) and saves the command (CMD) to MRQ, then calls the Mmc_wait_for_req function in section 4.1 to send cmd.

We can see from the parameters of this function that all the CMD needs to be sent are encapsulated by Mmc_command, which is mmc_request inside the function.
The structure is packaged again, and the mmc_request is delivered to the MMC controller driver to complete the dispatch of CMD.

Then look at the sending function of the ACMD command mmc_wait_for_app_cmd:

The following code is located in Linux/drivers/mmc/core/sd_ops.h.

/** * Mmc_wait_for_app_cmd-start A application command and wait for completion * @host: MMC host to start Command * @card: card to send mmc_app_cmd to * @cmd: MMC command to start * @retries: Maximum number of retries * * S Ends a mmc_app_cmd, checks the card response, sends the command * in the parameter and waits for it to complete.  Return any error * which occurred while the command is executing.
 Don't attempt to * parse the response.  * * int mmc_wait_for_app_cmd (struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) {struct

	Mmc_request Mrq = {NULL};

	int I, err;
	BUG_ON (!cmd);

	bug_on (Retries < 0);

	err =-eio;
	 /* We have to resend mmc_app_cmd for each attempt so * We cannot use the retries field in Mmc_command.
		* for (i = 0;i <= retries;i++) {* * send cmd55*/err = mmc_app_cmd (host, card); if (err) {/* no point in retrying; no APP commands allowed/if (MMC_HOST_IS_SPI (host)) {if (cmd-> resp[0] & R1_spi_illegal_command) break;
		} continue;

		memset (&AMP;MRQ, 0, sizeof (struct mmc_request));
		memset (cmd->resp, 0, sizeof (CMD-&GT;RESP));

		cmd->retries = 0;
		Mrq.cmd = cmd;

		Cmd->data = NULL;

		/* Send acmdx*/mmc_wait_for_req (host, &AMP;MRQ);
		Err = cmd->error;

		/* Send success, direct break and return * * (!cmd->error) break; /* No point in retrying illegal APP commands/if (MMC_HOST_IS_SPI (host)) {if (Cmd->resp[0] & R1_spi_illegal
		_command) break;
} return err; } export_symbol (Mmc_wait_for_app_cmd);
The function's formal parameter cmd saves the ACMD command that is sent on behalf of.

According to the requirements of SD card specification: Before sending the ACMD command, you need to send CMD55 to indicate that the following command is AMD command.

So, the function first calls the Mmc_app_cmd function to send the CMD55 command, so let's take a look at this function:

int mmc_app_cmd (struct mmc_host *host, struct Mmc_card *card)
{
	int err;
	struct Mmc_command cmd = {0};

	BUG_ON (!host);
	BUG_ON (Card && (card->host!= host));

	Cmd.opcode = Mmc_app_cmd;	/* CMD55 *

	/if (card) {
		cmd.arg = Card->rca <<;	/* Card Address * *
		cmd.flags = MMC_RSP_SPI_R1 | Mmc_rsp_r1 | Mmc_cmd_ac;
	} else {
		Cmd.arg = 0;	/* Card Address * *
		cmd.flags = MMC_RSP_SPI_R1 | Mmc_rsp_r1 | mmc_cmd_bcr;
	}

	/* Send cmd and wait (blocking mode)/
	err = Mmc_wait_for_cmd (host, &cmd, 0);
	if (ERR) return
		err;
	Host) &&! (Cmd.resp[0] & r1_app_cmd))
		Return-eopnotsupp;

	return 0;
}
EXPORT_SYMBOL_GPL (Mmc_app_cmd);
Let's take a look at the instructions for CMD55 in the SD specification:


From the description of the above command, we can see that:

1 The command is the AC type command, which is the point-to-point command, and there is no data transfer on the DAT signal line.
2 Second, the parameters of the command (31 to 16 digits) are RCA, which is the address of the card.

3 Finally, the command's response data format is R1.

Back to the function.

Cmd.arg for the parameters that send the command, the function first sets the parameter of the command to the SD card address (RCA), which conforms to the above description.

The Mmc_wait_for_cmd function that was previously parsed is then invoked to send the CMD55 command.

The response to the CMD55 command mentioned above is R1, and the format is as follows:


The card status of 32bit is stored in the RESP array as the response data.

The specific bit definition of card status please view the 4.10.1 summary of the SD specification.

Finally, check the CMD55 response to determine if the SD card supports the ACMD command.

Once the CMD55 is sent, return to the Mmc_wait_for_app_cmd function.

Then, CMD is saved to Mrq.cmd and calls Mmc_wait_for_req to send the ACMD command.

v. Summary

This paper briefly introduces the architecture of MMC subsystem, and gives some key data structures. At the same time, the initialization process of MMC subsystem is analyzed briefly, finally, the dispatch function of CMD and ACMD command is introduced emphatically.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.