All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
@ 2015-08-19  5:54 Chin Liang See
  2015-08-19  7:26 ` Pavel Machek
  2015-08-19  7:40 ` Marek Vasut
  0 siblings, 2 replies; 40+ messages in thread
From: Chin Liang See @ 2015-08-19  5:54 UTC (permalink / raw)
  To: u-boot

Enable SDMMC calibration to determine the best setting for
drvsel and smpsel. It will be triggered whenever there is
a change of card frequency and bus width. This is to ensure
reliable transmission between the controller and the card.

Signed-off-by: Chin Liang See <clsee@altera.com>
Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
Cc: Pavel Machek <pavel@denx.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Stefan Roese <sr@denx.de>
Cc: Tom Rini <trini@konsulko.com>
---
 drivers/mmc/socfpga_dw_mmc.c |  187 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 180 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index eb69aed..15e537c 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -11,25 +11,140 @@
 #include <asm/arch/dwmmc.h>
 #include <asm/arch/clock_manager.h>
 #include <asm/arch/system_manager.h>
+#include "mmc_private.h"
 
 static const struct socfpga_clock_manager *clock_manager_base =
 		(void *)SOCFPGA_CLKMGR_ADDRESS;
 static const struct socfpga_system_manager *system_manager_base =
 		(void *)SOCFPGA_SYSMGR_ADDRESS;
 
-static void socfpga_dwmci_clksel(struct dwmci_host *host)
+#define CAL_ROWS     7
+#define CAL_COLS     8
+
+/*
+ * This function determines the largest rectangle filled with 1's and returns
+ * the middle. This functon can be optimized, for example using the algorithm
+ * from http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
+ * It currently takes less than 1ms, while creating the input data takes ~5ms
+ * so there is not a real need to optimize it.
+ */
+int find_calibration_point(unsigned char cal_results[CAL_ROWS][CAL_COLS],
+unsigned int sum, unsigned int * cal_row, unsigned int * cal_col)
 {
-	unsigned int drvsel;
-	unsigned int smplsel;
+	/* Structure containing a rectangle candidate */
+	typedef struct
+	{
+		unsigned char height;
+		unsigned char width;
+		unsigned short area;
+	} rect_cand_t;
+
+	/* Array with the rectangle candidates */
+	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
+	unsigned char cr_rect_cand = 0;
+	unsigned char height, width, k;
+
+	/* No solution if all combinations fail */
+	if(sum == 0)
+		return 1;
+
+	/* Simple solution if all combinations pass */
+	if(sum == (CAL_ROWS * CAL_COLS)) {
+		*cal_row = (CAL_ROWS - 1) / 2;
+		*cal_col = (CAL_COLS - 1) / 2;
+		return 0;
+	}
+
+	/*
+	 * Create list of all possible sub-rectangles, in descending area
+	 * order
+	 */
+	for(height = CAL_ROWS; height >= 1; height--) {
+		for(width = CAL_COLS; width >= 1 ; width--){
+			/* Add a new rectangle candidate */
+			rect_cands[cr_rect_cand].height = height;
+			rect_cands[cr_rect_cand].width = width;
+			rect_cands[cr_rect_cand].area = height * width;
+			cr_rect_cand++;
+
+			/* First candidate it always in the right position */
+			if(cr_rect_cand == 1)
+				continue;
+
+			/*
+			 * Put the candidate in right location to maintain
+			 * descending order
+			 */
+			for(k = cr_rect_cand - 1; k > 1; k--){
+				if(rect_cands[k-1].area < rect_cands[k].area){
+					rect_cand_t tmp = rect_cands[k-1];
+					rect_cands[k-1] = rect_cands[k];
+					rect_cands[k] = tmp;
+				} else
+					break;
+			}
+		}
+	}
+
+	/* Try to fit the rectangle candidates, in descending area order */
+	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
+		unsigned char start_row, start_col;
+		unsigned rect_width = rect_cands[k].width;
+		unsigned rect_height = rect_cands[k].height;
+
+		/* Find the row and column where the candidate fits */
+		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
+		     start_col++) {
+			for (start_row = 0; start_row < (CAL_ROWS -
+			     rect_height + 1); start_row++) {
+				unsigned ok = 1;
+				unsigned add_col, add_row;
+
+				/* Determine if the rectangle fits here */
+				for (add_col = 0; (add_col < rect_width) && ok;
+				     add_col++) {
+					for (add_row = 0; add_row < rect_height;
+					     add_row++) {
+						if (!cal_results
+						   [start_row+add_row][start_col
+						   + add_col]) {
+							ok = 0;
+							break;
+						}
+					}
+				}
+
+				/*
+				 * Return 'middle' of rectangle in case of
+				 * success
+				 */
+				if (ok) {
+					if(rect_width > 1)
+						rect_width--;
+
+					if(rect_height > 1)
+						rect_height--;
+
+					*cal_row = start_row +
+						   (rect_height / 2);
+					*cal_col = start_col + (rect_width / 2);
+
+					return 0;
+				}
+			}
+		}
+	}
+
+	/* We could not fit any rectangle - return failure */
+	return 1;
+}
 
+void socfpga_dwmmc_set_clksel(unsigned int drvsel, unsigned int smplsel)
+{
 	/* Disable SDMMC clock. */
 	clrbits_le32(&clock_manager_base->per_pll.en,
 		CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
 
-	/* Configures drv_sel and smpl_sel */
-	drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL;
-	smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL;
-
 	debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel);
 	writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel),
 		&system_manager_base->sdmmcgrp_ctrl);
@@ -42,6 +157,64 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host)
 		CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
 }
 
+/*
+ * This functions calirates the drvsel and smplsel by trying all possible
+ * values and selecting the best combnation
+ */
+void socfpga_dwmmc_calibrate(struct dwmci_host *host)
+{
+	int err = 0;
+	unsigned char cal_results[CAL_ROWS][CAL_COLS];
+	unsigned int sum = 0;
+	unsigned int row, col, drvsel, smplsel;
+
+	struct mmc *mmc = (struct mmc *)host->mmc;
+	if (mmc == NULL) {
+		printf("struct mmc is NULL\n");
+		hang();
+	}
+
+	printf("%s: Calibration started.\n", __func__);
+
+	for (row = 0; row < CAL_ROWS; row++) {
+		for (col = 0; col < CAL_COLS; col++) {
+			drvsel = row + 1;
+			smplsel = col;
+			socfpga_dwmmc_set_clksel(drvsel, smplsel);
+			cal_results[row][col] = !(mmc_set_blocklen(mmc,
+						  mmc->read_bl_len));
+			sum += cal_results[row][col];
+		}
+	}
+
+	debug("%s: Calibration raw data:\n", __func__);
+	for(row = 0; row < CAL_ROWS; row++) {
+		debug("\t");
+		for(col = 0; col < CAL_COLS; col++)
+			debug("%d ", cal_results[row][col]);
+		debug("\n");
+	}
+
+	err = find_calibration_point(cal_results, sum, &drvsel, &smplsel);
+
+	if(err) {
+		printf("%s: Calibration failed.\n", __func__);
+		hang();
+	} else
+		printf("%s: Calibration passed: drvsel = %d "
+		       "smplsel = %d.\n", __func__, drvsel, smplsel);
+
+	socfpga_dwmmc_set_clksel(drvsel, smplsel);
+
+	/* re-write in case accidentally overwrite with junk */
+	mmc_set_blocklen(mmc, mmc->read_bl_len);
+}
+
+void socfpga_dwmci_clksel(struct dwmci_host *host)
+{
+	socfpga_dwmmc_calibrate(host);
+}
+
 int socfpga_dwmmc_init(u32 regbase, int bus_width, int index)
 {
 	struct dwmci_host *host;
-- 
1.7.7.4

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  5:54 [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel Chin Liang See
@ 2015-08-19  7:26 ` Pavel Machek
  2015-08-19  7:34   ` Marek Vasut
  2015-08-19  8:33   ` Chin Liang See
  2015-08-19  7:40 ` Marek Vasut
  1 sibling, 2 replies; 40+ messages in thread
From: Pavel Machek @ 2015-08-19  7:26 UTC (permalink / raw)
  To: u-boot

On Wed 2015-08-19 00:54:50, Chin Liang See wrote:
> Enable SDMMC calibration to determine the best setting for
> drvsel and smpsel. It will be triggered whenever there is
> a change of card frequency and bus width. This is to ensure
> reliable transmission between the controller and the card.
> 
> Signed-off-by: Chin Liang See <clsee@altera.com>
> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> Cc: Pavel Machek <pavel@denx.de>
> Cc: Marek Vasut <marex@denx.de>
> Cc: Wolfgang Denk <wd@denx.de>
> Cc: Stefan Roese <sr@denx.de>
> Cc: Tom Rini <trini@konsulko.com>
> ---
>  drivers/mmc/socfpga_dw_mmc.c |  187 ++++++++++++++++++++++++++++++++++++++++--
>  1 files changed, 180 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
> index eb69aed..15e537c 100644
> --- a/drivers/mmc/socfpga_dw_mmc.c
> +++ b/drivers/mmc/socfpga_dw_mmc.c
> @@ -11,25 +11,140 @@
>  #include <asm/arch/dwmmc.h>
>  #include <asm/arch/clock_manager.h>
>  #include <asm/arch/system_manager.h>
> +#include "mmc_private.h"
>  
>  static const struct socfpga_clock_manager *clock_manager_base =
>  		(void *)SOCFPGA_CLKMGR_ADDRESS;
>  static const struct socfpga_system_manager *system_manager_base =
>  		(void *)SOCFPGA_SYSMGR_ADDRESS;
>  
> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> +#define CAL_ROWS     7
> +#define CAL_COLS     8
> +
> +/*
> + * This function determines the largest rectangle filled with 1's and returns
> + * the middle. This functon can be optimized, for example using the algorithm
> + * from
http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529

Actually, I'd like to see optimized version.  It has potential to be
easier to read...

> + * It currently takes less than 1ms, while creating the input data takes ~5ms
> + * so there is not a real need to optimize it.
> + */
> +int find_calibration_point(unsigned char cal_results[CAL_ROWS][CAL_COLS],
> +unsigned int sum, unsigned int * cal_row, unsigned int * cal_col)
>  {
> -	unsigned int drvsel;
> -	unsigned int smplsel;
> +	/* Structure containing a rectangle candidate */
> +	typedef struct
> +	{
> +		unsigned char height;
> +		unsigned char width;
> +		unsigned short area;
> +	} rect_cand_t;
> +
> +	/* Array with the rectangle candidates */
> +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> +	unsigned char cr_rect_cand = 0;
> +	unsigned char height, width, k;
> +
> +	/* No solution if all combinations fail */
> +	if(sum == 0)
> +		return 1;

Codingstyle: "if ("

> +	/*
> +	 * Create list of all possible sub-rectangles, in descending area
> +	 * order
> +	 */
> +	for(height = CAL_ROWS; height >= 1; height--) {
> +		for(width = CAL_COLS; width >= 1 ; width--){

No space before ;.


> +	/* Try to fit the rectangle candidates, in descending area order */
> +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> +		unsigned char start_row, start_col;
> +		unsigned rect_width = rect_cands[k].width;
> +		unsigned rect_height = rect_cands[k].height;
> +
> +		/* Find the row and column where the candidate fits */
> +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> +		     start_col++) {
> +			for (start_row = 0; start_row < (CAL_ROWS -
> +			     rect_height + 1); start_row++) {
> +				unsigned ok = 1;
> +				unsigned add_col, add_row;
> +
> +				/* Determine if the rectangle fits here */
> +				for (add_col = 0; (add_col < rect_width) && ok;
> +				     add_col++) {
> +					for (add_row = 0; add_row < rect_height;
> +					     add_row++) {
> +						if (!cal_results
> +						   [start_row+add_row][start_col
> +						   + add_col]) {
> +							ok = 0;
> +							break;

Create separate functions to make it easier to read and less indented.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  7:26 ` Pavel Machek
@ 2015-08-19  7:34   ` Marek Vasut
  2015-08-19  8:30     ` Chin Liang See
  2015-08-19  8:33   ` Chin Liang See
  1 sibling, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-08-19  7:34 UTC (permalink / raw)
  To: u-boot

On Wednesday, August 19, 2015 at 09:26:55 AM, Pavel Machek wrote:
> On Wed 2015-08-19 00:54:50, Chin Liang See wrote:
> > Enable SDMMC calibration to determine the best setting for
> > drvsel and smpsel. It will be triggered whenever there is
> > a change of card frequency and bus width. This is to ensure
> > reliable transmission between the controller and the card.
> > 
> > Signed-off-by: Chin Liang See <clsee@altera.com>
> > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > Cc: Pavel Machek <pavel@denx.de>
> > Cc: Marek Vasut <marex@denx.de>
> > Cc: Wolfgang Denk <wd@denx.de>

I guess there's no need to CC Wolfgang and Tom on SoCFPGA-specific stuff.

> > Cc: Stefan Roese <sr@denx.de>
> > Cc: Tom Rini <trini@konsulko.com>
> > ---

Hi!

> >  drivers/mmc/socfpga_dw_mmc.c |  187
> >  ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> >  insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
> > index eb69aed..15e537c 100644
> > --- a/drivers/mmc/socfpga_dw_mmc.c
> > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > @@ -11,25 +11,140 @@
> > 
> >  #include <asm/arch/dwmmc.h>
> >  #include <asm/arch/clock_manager.h>
> >  #include <asm/arch/system_manager.h>
> > 
> > +#include "mmc_private.h"
> > 
> >  static const struct socfpga_clock_manager *clock_manager_base =
> >  
> >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> >  
> >  static const struct socfpga_system_manager *system_manager_base =
> >  
> >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> > 
> > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > +#define CAL_ROWS     7
> > +#define CAL_COLS     8

What is this ugliness needed for ?

btw. Please rebase on top of u-boot-socfpga/master .

> > +/*
> > + * This function determines the largest rectangle filled with 1's and
> > returns + * the middle. This functon can be optimized, for example using
> > the algorithm + * from
> 
> http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
> 
> Actually, I'd like to see optimized version.  It has potential to be
> easier to read...
> 
> > + * It currently takes less than 1ms, while creating the input data takes
> > ~5ms + * so there is not a real need to optimize it.
> > + */
> > +int find_calibration_point(unsigned char
> > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> > cal_row, unsigned int * cal_col)
> > 
> >  {
> > 
> > -	unsigned int drvsel;
> > -	unsigned int smplsel;
> > +	/* Structure containing a rectangle candidate */
> > +	typedef struct
> > +	{
> > +		unsigned char height;
> > +		unsigned char width;
> > +		unsigned short area;
> > +	} rect_cand_t;

Also get rid of this typedef monster.

> > +	/* Array with the rectangle candidates */
> > +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > +	unsigned char cr_rect_cand = 0;
> > +	unsigned char height, width, k;
> > +
> > +	/* No solution if all combinations fail */
> > +	if(sum == 0)
> > +		return 1;
> 
> Codingstyle: "if ("
> 
> > +	/*
> > +	 * Create list of all possible sub-rectangles, in descending area
> > +	 * order
> > +	 */
> > +	for(height = CAL_ROWS; height >= 1; height--) {
> > +		for(width = CAL_COLS; width >= 1 ; width--){
> 
> No space before ;.
> 
> > +	/* Try to fit the rectangle candidates, in descending area order */
> > +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > +		unsigned char start_row, start_col;
> > +		unsigned rect_width = rect_cands[k].width;
> > +		unsigned rect_height = rect_cands[k].height;
> > +
> > +		/* Find the row and column where the candidate fits */
> > +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> > +		     start_col++) {
> > +			for (start_row = 0; start_row < (CAL_ROWS -
> > +			     rect_height + 1); start_row++) {
> > +				unsigned ok = 1;
> > +				unsigned add_col, add_row;
> > +
> > +				/* Determine if the rectangle fits here */
> > +				for (add_col = 0; (add_col < rect_width) && ok;
> > +				     add_col++) {
> > +					for (add_row = 0; add_row < rect_height;
> > +					     add_row++) {
> > +						if (!cal_results
> > +						   [start_row+add_row][start_col
> > +						   + add_col]) {
> > +							ok = 0;
> > +							break;
> 
> Create separate functions to make it easier to read and less indented.

Right.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  5:54 [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel Chin Liang See
  2015-08-19  7:26 ` Pavel Machek
@ 2015-08-19  7:40 ` Marek Vasut
  2015-08-19  8:21   ` Chin Liang See
  1 sibling, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-08-19  7:40 UTC (permalink / raw)
  To: u-boot

On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> Enable SDMMC calibration to determine the best setting for
> drvsel and smpsel. It will be triggered whenever there is
> a change of card frequency and bus width. This is to ensure
> reliable transmission between the controller and the card.
> 
> Signed-off-by: Chin Liang See <clsee@altera.com>
> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> Cc: Pavel Machek <pavel@denx.de>
> Cc: Marek Vasut <marex@denx.de>
> Cc: Wolfgang Denk <wd@denx.de>
> Cc: Stefan Roese <sr@denx.de>
> Cc: Tom Rini <trini@konsulko.com>
> ---
>  drivers/mmc/socfpga_dw_mmc.c |  187
> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
> index eb69aed..15e537c 100644
> --- a/drivers/mmc/socfpga_dw_mmc.c
> +++ b/drivers/mmc/socfpga_dw_mmc.c
> @@ -11,25 +11,140 @@
>  #include <asm/arch/dwmmc.h>
>  #include <asm/arch/clock_manager.h>
>  #include <asm/arch/system_manager.h>
> +#include "mmc_private.h"
> 
>  static const struct socfpga_clock_manager *clock_manager_base =
>  		(void *)SOCFPGA_CLKMGR_ADDRESS;
>  static const struct socfpga_system_manager *system_manager_base =
>  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> 
> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> +#define CAL_ROWS     7
> +#define CAL_COLS     8
> +
> +/*
> + * This function determines the largest rectangle filled with 1's and
> returns + * the middle. This functon can be optimized, for example using
> the algorithm + * from
> http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529 +
> * It currently takes less than 1ms, while creating the input data takes
> ~5ms + * so there is not a real need to optimize it.
> + */
> +int find_calibration_point(unsigned char cal_results[CAL_ROWS][CAL_COLS],
> +unsigned int sum, unsigned int * cal_row, unsigned int * cal_col)
>  {
> -	unsigned int drvsel;
> -	unsigned int smplsel;
> +	/* Structure containing a rectangle candidate */
> +	typedef struct
> +	{
> +		unsigned char height;
> +		unsigned char width;
> +		unsigned short area;
> +	} rect_cand_t;
> +
> +	/* Array with the rectangle candidates */
> +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> +	unsigned char cr_rect_cand = 0;
> +	unsigned char height, width, k;
> +
> +	/* No solution if all combinations fail */
> +	if(sum == 0)
> +		return 1;
> +
> +	/* Simple solution if all combinations pass */
> +	if(sum == (CAL_ROWS * CAL_COLS)) {
> +		*cal_row = (CAL_ROWS - 1) / 2;
> +		*cal_col = (CAL_COLS - 1) / 2;
> +		return 0;
> +	}
> +
> +	/*
> +	 * Create list of all possible sub-rectangles, in descending area
> +	 * order
> +	 */
> +	for(height = CAL_ROWS; height >= 1; height--) {
> +		for(width = CAL_COLS; width >= 1 ; width--){
> +			/* Add a new rectangle candidate */
> +			rect_cands[cr_rect_cand].height = height;
> +			rect_cands[cr_rect_cand].width = width;
> +			rect_cands[cr_rect_cand].area = height * width;
> +			cr_rect_cand++;
> +
> +			/* First candidate it always in the right position */
> +			if(cr_rect_cand == 1)
> +				continue;
> +
> +			/*
> +			 * Put the candidate in right location to maintain
> +			 * descending order
> +			 */
> +			for(k = cr_rect_cand - 1; k > 1; k--){
> +				if(rect_cands[k-1].area < rect_cands[k].area){
> +					rect_cand_t tmp = rect_cands[k-1];
> +					rect_cands[k-1] = rect_cands[k];
> +					rect_cands[k] = tmp;
> +				} else
> +					break;
> +			}
> +		}
> +	}
> +
> +	/* Try to fit the rectangle candidates, in descending area order */
> +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> +		unsigned char start_row, start_col;
> +		unsigned rect_width = rect_cands[k].width;
> +		unsigned rect_height = rect_cands[k].height;
> +
> +		/* Find the row and column where the candidate fits */
> +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> +		     start_col++) {
> +			for (start_row = 0; start_row < (CAL_ROWS -
> +			     rect_height + 1); start_row++) {
> +				unsigned ok = 1;
> +				unsigned add_col, add_row;
> +
> +				/* Determine if the rectangle fits here */
> +				for (add_col = 0; (add_col < rect_width) && ok;
> +				     add_col++) {
> +					for (add_row = 0; add_row < rect_height;
> +					     add_row++) {
> +						if (!cal_results
> +						   [start_row+add_row][start_col
> +						   + add_col]) {
> +							ok = 0;
> +							break;
> +						}
> +					}
> +				}
> +
> +				/*
> +				 * Return 'middle' of rectangle in case of
> +				 * success
> +				 */
> +				if (ok) {
> +					if(rect_width > 1)
> +						rect_width--;
> +
> +					if(rect_height > 1)
> +						rect_height--;
> +
> +					*cal_row = start_row +
> +						   (rect_height / 2);
> +					*cal_col = start_col + (rect_width / 2);
> +
> +					return 0;
> +				}
> +			}
> +		}
> +	}
> +
> +	/* We could not fit any rectangle - return failure */
> +	return 1;

Oh btw. please make sure to use errno.h and standard return codes ; -EINVAL in 
this case I believe.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  7:40 ` Marek Vasut
@ 2015-08-19  8:21   ` Chin Liang See
  2015-08-19 19:36     ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-08-19  8:21 UTC (permalink / raw)
  To: u-boot

Hi,

On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> > Enable SDMMC calibration to determine the best setting for
> > drvsel and smpsel. It will be triggered whenever there is
> > a change of card frequency and bus width. This is to ensure
> > reliable transmission between the controller and the card.
> > 
> > Signed-off-by: Chin Liang See <clsee@altera.com>
> > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > Cc: Pavel Machek <pavel@denx.de>
> > Cc: Marek Vasut <marex@denx.de>
> > Cc: Wolfgang Denk <wd@denx.de>
> > Cc: Stefan Roese <sr@denx.de>
> > Cc: Tom Rini <trini@konsulko.com>
> > ---
> >  drivers/mmc/socfpga_dw_mmc.c |  187
> > ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> > insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
> > index eb69aed..15e537c 100644
> > --- a/drivers/mmc/socfpga_dw_mmc.c
> > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > @@ -11,25 +11,140 @@
> >  #include <asm/arch/dwmmc.h>
> >  #include <asm/arch/clock_manager.h>
> >  #include <asm/arch/system_manager.h>
> > +#include "mmc_private.h"
> > 
> >  static const struct socfpga_clock_manager *clock_manager_base =
> >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> >  static const struct socfpga_system_manager *system_manager_base =
> >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> > 
> > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > +#define CAL_ROWS     7
> > +#define CAL_COLS     8
> > +
> > +/*
> > + * This function determines the largest rectangle filled with 1's and
> > returns + * the middle. This functon can be optimized, for example using
> > the algorithm + * from
> > http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529 +
> > * It currently takes less than 1ms, while creating the input data takes
> > ~5ms + * so there is not a real need to optimize it.
> > + */
> > +int find_calibration_point(unsigned char cal_results[CAL_ROWS][CAL_COLS],
> > +unsigned int sum, unsigned int * cal_row, unsigned int * cal_col)
> >  {
> > -	unsigned int drvsel;
> > -	unsigned int smplsel;
> > +	/* Structure containing a rectangle candidate */
> > +	typedef struct
> > +	{
> > +		unsigned char height;
> > +		unsigned char width;
> > +		unsigned short area;
> > +	} rect_cand_t;
> > +
> > +	/* Array with the rectangle candidates */
> > +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > +	unsigned char cr_rect_cand = 0;
> > +	unsigned char height, width, k;
> > +
> > +	/* No solution if all combinations fail */
> > +	if(sum == 0)
> > +		return 1;
> > +
> > +	/* Simple solution if all combinations pass */
> > +	if(sum == (CAL_ROWS * CAL_COLS)) {
> > +		*cal_row = (CAL_ROWS - 1) / 2;
> > +		*cal_col = (CAL_COLS - 1) / 2;
> > +		return 0;
> > +	}
> > +
> > +	/*
> > +	 * Create list of all possible sub-rectangles, in descending area
> > +	 * order
> > +	 */
> > +	for(height = CAL_ROWS; height >= 1; height--) {
> > +		for(width = CAL_COLS; width >= 1 ; width--){
> > +			/* Add a new rectangle candidate */
> > +			rect_cands[cr_rect_cand].height = height;
> > +			rect_cands[cr_rect_cand].width = width;
> > +			rect_cands[cr_rect_cand].area = height * width;
> > +			cr_rect_cand++;
> > +
> > +			/* First candidate it always in the right position */
> > +			if(cr_rect_cand == 1)
> > +				continue;
> > +
> > +			/*
> > +			 * Put the candidate in right location to maintain
> > +			 * descending order
> > +			 */
> > +			for(k = cr_rect_cand - 1; k > 1; k--){
> > +				if(rect_cands[k-1].area < rect_cands[k].area){
> > +					rect_cand_t tmp = rect_cands[k-1];
> > +					rect_cands[k-1] = rect_cands[k];
> > +					rect_cands[k] = tmp;
> > +				} else
> > +					break;
> > +			}
> > +		}
> > +	}
> > +
> > +	/* Try to fit the rectangle candidates, in descending area order */
> > +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > +		unsigned char start_row, start_col;
> > +		unsigned rect_width = rect_cands[k].width;
> > +		unsigned rect_height = rect_cands[k].height;
> > +
> > +		/* Find the row and column where the candidate fits */
> > +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> > +		     start_col++) {
> > +			for (start_row = 0; start_row < (CAL_ROWS -
> > +			     rect_height + 1); start_row++) {
> > +				unsigned ok = 1;
> > +				unsigned add_col, add_row;
> > +
> > +				/* Determine if the rectangle fits here */
> > +				for (add_col = 0; (add_col < rect_width) && ok;
> > +				     add_col++) {
> > +					for (add_row = 0; add_row < rect_height;
> > +					     add_row++) {
> > +						if (!cal_results
> > +						   [start_row+add_row][start_col
> > +						   + add_col]) {
> > +							ok = 0;
> > +							break;
> > +						}
> > +					}
> > +				}
> > +
> > +				/*
> > +				 * Return 'middle' of rectangle in case of
> > +				 * success
> > +				 */
> > +				if (ok) {
> > +					if(rect_width > 1)
> > +						rect_width--;
> > +
> > +					if(rect_height > 1)
> > +						rect_height--;
> > +
> > +					*cal_row = start_row +
> > +						   (rect_height / 2);
> > +					*cal_col = start_col + (rect_width / 2);
> > +
> > +					return 0;
> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	/* We could not fit any rectangle - return failure */
> > +	return 1;
> 
> Oh btw. please make sure to use errno.h and standard return codes ; -EINVAL in 
> this case I believe.

Good suggestion, will fix in v2.
Thanks

Chin Liang

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  7:34   ` Marek Vasut
@ 2015-08-19  8:30     ` Chin Liang See
  2015-08-19 23:23       ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-08-19  8:30 UTC (permalink / raw)
  To: u-boot

Him

On Wed, 2015-08-19 at 09:34 +0200, marex at denx.de wrote:
> On Wednesday, August 19, 2015 at 09:26:55 AM, Pavel Machek wrote:
> > On Wed 2015-08-19 00:54:50, Chin Liang See wrote:
> > > Enable SDMMC calibration to determine the best setting for
> > > drvsel and smpsel. It will be triggered whenever there is
> > > a change of card frequency and bus width. This is to ensure
> > > reliable transmission between the controller and the card.
> > > 
> > > Signed-off-by: Chin Liang See <clsee@altera.com>
> > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > > Cc: Pavel Machek <pavel@denx.de>
> > > Cc: Marek Vasut <marex@denx.de>
> > > Cc: Wolfgang Denk <wd@denx.de>
> 
> I guess there's no need to CC Wolfgang and Tom on SoCFPGA-specific stuff.

Sure, I was referring to the previous patch for the mailing list :)

> 
> > > Cc: Stefan Roese <sr@denx.de>
> > > Cc: Tom Rini <trini@konsulko.com>
> > > ---
> 
> Hi!
> 
> > >  drivers/mmc/socfpga_dw_mmc.c |  187
> > >  ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> > >  insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
> > > index eb69aed..15e537c 100644
> > > --- a/drivers/mmc/socfpga_dw_mmc.c
> > > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > > @@ -11,25 +11,140 @@
> > > 
> > >  #include <asm/arch/dwmmc.h>
> > >  #include <asm/arch/clock_manager.h>
> > >  #include <asm/arch/system_manager.h>
> > > 
> > > +#include "mmc_private.h"
> > > 
> > >  static const struct socfpga_clock_manager *clock_manager_base =
> > >  
> > >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> > >  
> > >  static const struct socfpga_system_manager *system_manager_base =
> > >  
> > >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> > > 
> > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > > +#define CAL_ROWS     7
> > > +#define CAL_COLS     8
> 
> What is this ugliness needed for ?

Actually this is used to create the rectangle based on the result.
We are doing the shmoo test for the parameter smpsel and drvsel.

> 
> btw. Please rebase on top of u-boot-socfpga/master .

Sure, just saw new changes has been added for last few hours.

> 
> > > +/*
> > > + * This function determines the largest rectangle filled with 1's and
> > > returns + * the middle. This functon can be optimized, for example using
> > > the algorithm + * from
> > 
> > http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
> > 
> > Actually, I'd like to see optimized version.  It has potential to be
> > easier to read...
> > 
> > > + * It currently takes less than 1ms, while creating the input data takes
> > > ~5ms + * so there is not a real need to optimize it.
> > > + */
> > > +int find_calibration_point(unsigned char
> > > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> > > cal_row, unsigned int * cal_col)
> > > 
> > >  {
> > > 
> > > -	unsigned int drvsel;
> > > -	unsigned int smplsel;
> > > +	/* Structure containing a rectangle candidate */
> > > +	typedef struct
> > > +	{
> > > +		unsigned char height;
> > > +		unsigned char width;
> > > +		unsigned short area;
> > > +	} rect_cand_t;
> 
> Also get rid of this typedef monster.

Make sense as we are using here only.


> 
> > > +	/* Array with the rectangle candidates */
> > > +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > > +	unsigned char cr_rect_cand = 0;
> > > +	unsigned char height, width, k;
> > > +
> > > +	/* No solution if all combinations fail */
> > > +	if(sum == 0)
> > > +		return 1;
> > 
> > Codingstyle: "if ("
> > 
> > > +	/*
> > > +	 * Create list of all possible sub-rectangles, in descending area
> > > +	 * order
> > > +	 */
> > > +	for(height = CAL_ROWS; height >= 1; height--) {
> > > +		for(width = CAL_COLS; width >= 1 ; width--){
> > 
> > No space before ;.
> > 
> > > +	/* Try to fit the rectangle candidates, in descending area order */
> > > +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > > +		unsigned char start_row, start_col;
> > > +		unsigned rect_width = rect_cands[k].width;
> > > +		unsigned rect_height = rect_cands[k].height;
> > > +
> > > +		/* Find the row and column where the candidate fits */
> > > +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> > > +		     start_col++) {
> > > +			for (start_row = 0; start_row < (CAL_ROWS -
> > > +			     rect_height + 1); start_row++) {
> > > +				unsigned ok = 1;
> > > +				unsigned add_col, add_row;
> > > +
> > > +				/* Determine if the rectangle fits here */
> > > +				for (add_col = 0; (add_col < rect_width) && ok;
> > > +				     add_col++) {
> > > +					for (add_row = 0; add_row < rect_height;
> > > +					     add_row++) {
> > > +						if (!cal_results
> > > +						   [start_row+add_row][start_col
> > > +						   + add_col]) {
> > > +							ok = 0;
> > > +							break;
> > 
> > Create separate functions to make it easier to read and less indented.
> 
> Right.

Let me crank my head on this :)
Thanks

Chin Liang

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  7:26 ` Pavel Machek
  2015-08-19  7:34   ` Marek Vasut
@ 2015-08-19  8:33   ` Chin Liang See
  1 sibling, 0 replies; 40+ messages in thread
From: Chin Liang See @ 2015-08-19  8:33 UTC (permalink / raw)
  To: u-boot

Hi,

On Wed, 2015-08-19 at 09:26 +0200, ZY - pavel wrote:
> On Wed 2015-08-19 00:54:50, Chin Liang See wrote:
> > Enable SDMMC calibration to determine the best setting for
> > drvsel and smpsel. It will be triggered whenever there is
> > a change of card frequency and bus width. This is to ensure
> > reliable transmission between the controller and the card.
> > 
> > Signed-off-by: Chin Liang See <clsee@altera.com>
> > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > Cc: Pavel Machek <pavel@denx.de>
> > Cc: Marek Vasut <marex@denx.de>
> > Cc: Wolfgang Denk <wd@denx.de>
> > Cc: Stefan Roese <sr@denx.de>
> > Cc: Tom Rini <trini@konsulko.com>
> > ---
> >  drivers/mmc/socfpga_dw_mmc.c |  187 ++++++++++++++++++++++++++++++++++++++++--
> >  1 files changed, 180 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
> > index eb69aed..15e537c 100644
> > --- a/drivers/mmc/socfpga_dw_mmc.c
> > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > @@ -11,25 +11,140 @@
> >  #include <asm/arch/dwmmc.h>
> >  #include <asm/arch/clock_manager.h>
> >  #include <asm/arch/system_manager.h>
> > +#include "mmc_private.h"
> >  
> >  static const struct socfpga_clock_manager *clock_manager_base =
> >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> >  static const struct socfpga_system_manager *system_manager_base =
> >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> >  
> > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > +#define CAL_ROWS     7
> > +#define CAL_COLS     8
> > +
> > +/*
> > + * This function determines the largest rectangle filled with 1's and returns
> > + * the middle. This functon can be optimized, for example using the algorithm
> > + * from
> http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
> 
> Actually, I'd like to see optimized version.  It has potential to be
> easier to read...
> 

Actually in this calibration, we should see a obvious rectangle.
We shouldn't have a fail in between the passes.


> > + * It currently takes less than 1ms, while creating the input data takes ~5ms
> > + * so there is not a real need to optimize it.
> > + */
> > +int find_calibration_point(unsigned char cal_results[CAL_ROWS][CAL_COLS],
> > +unsigned int sum, unsigned int * cal_row, unsigned int * cal_col)
> >  {
> > -	unsigned int drvsel;
> > -	unsigned int smplsel;
> > +	/* Structure containing a rectangle candidate */
> > +	typedef struct
> > +	{
> > +		unsigned char height;
> > +		unsigned char width;
> > +		unsigned short area;
> > +	} rect_cand_t;
> > +
> > +	/* Array with the rectangle candidates */
> > +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > +	unsigned char cr_rect_cand = 0;
> > +	unsigned char height, width, k;
> > +
> > +	/* No solution if all combinations fail */
> > +	if(sum == 0)
> > +		return 1;
> 
> Codingstyle: "if ("

Good catch, noted

> 
> > +	/*
> > +	 * Create list of all possible sub-rectangles, in descending area
> > +	 * order
> > +	 */
> > +	for(height = CAL_ROWS; height >= 1; height--) {
> > +		for(width = CAL_COLS; width >= 1 ; width--){
> 
> No space before ;.

Good catch, noted

> 
> 
> > +	/* Try to fit the rectangle candidates, in descending area order */
> > +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > +		unsigned char start_row, start_col;
> > +		unsigned rect_width = rect_cands[k].width;
> > +		unsigned rect_height = rect_cands[k].height;
> > +
> > +		/* Find the row and column where the candidate fits */
> > +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> > +		     start_col++) {
> > +			for (start_row = 0; start_row < (CAL_ROWS -
> > +			     rect_height + 1); start_row++) {
> > +				unsigned ok = 1;
> > +				unsigned add_col, add_row;
> > +
> > +				/* Determine if the rectangle fits here */
> > +				for (add_col = 0; (add_col < rect_width) && ok;
> > +				     add_col++) {
> > +					for (add_row = 0; add_row < rect_height;
> > +					     add_row++) {
> > +						if (!cal_results
> > +						   [start_row+add_row][start_col
> > +						   + add_col]) {
> > +							ok = 0;
> > +							break;
> 
> Create separate functions to make it easier to read and less indented.
> 

Will do, thanks

Chin Liang

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  8:21   ` Chin Liang See
@ 2015-08-19 19:36     ` Marek Vasut
  2015-08-20  5:28       ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-08-19 19:36 UTC (permalink / raw)
  To: u-boot

On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> Hi,

Hi again,

> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> > On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> > > Enable SDMMC calibration to determine the best setting for
> > > drvsel and smpsel. It will be triggered whenever there is
> > > a change of card frequency and bus width. This is to ensure
> > > reliable transmission between the controller and the card.
> > > 
> > > Signed-off-by: Chin Liang See <clsee@altera.com>
> > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > > Cc: Pavel Machek <pavel@denx.de>
> > > Cc: Marek Vasut <marex@denx.de>
> > > Cc: Wolfgang Denk <wd@denx.de>
> > > Cc: Stefan Roese <sr@denx.de>
> > > Cc: Tom Rini <trini@konsulko.com>
> > > ---
> > > 
> > >  drivers/mmc/socfpga_dw_mmc.c |  187
> > > 
> > > ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> > > insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > > b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> > > --- a/drivers/mmc/socfpga_dw_mmc.c
> > > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > > @@ -11,25 +11,140 @@
> > > 
> > >  #include <asm/arch/dwmmc.h>
> > >  #include <asm/arch/clock_manager.h>
> > >  #include <asm/arch/system_manager.h>
> > > 
> > > +#include "mmc_private.h"
> > > 
> > >  static const struct socfpga_clock_manager *clock_manager_base =
> > >  
> > >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> > >  
> > >  static const struct socfpga_system_manager *system_manager_base =
> > >  
> > >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> > > 
> > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > > +#define CAL_ROWS     7
> > > +#define CAL_COLS     8
> > > +
> > > +/*
> > > + * This function determines the largest rectangle filled with 1's and
> > > returns + * the middle. This functon can be optimized, for example
> > > using the algorithm + * from
> > > http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
> > > + * It currently takes less than 1ms, while creating the input data
> > > takes ~5ms + * so there is not a real need to optimize it.
> > > + */
> > > +int find_calibration_point(unsigned char
> > > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> > > cal_row, unsigned int * cal_col)
> > > 
> > >  {
> > > 
> > > -	unsigned int drvsel;
> > > -	unsigned int smplsel;
> > > +	/* Structure containing a rectangle candidate */
> > > +	typedef struct
> > > +	{
> > > +		unsigned char height;
> > > +		unsigned char width;
> > > +		unsigned short area;
> > > +	} rect_cand_t;
> > > +
> > > +	/* Array with the rectangle candidates */
> > > +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > > +	unsigned char cr_rect_cand = 0;
> > > +	unsigned char height, width, k;
> > > +
> > > +	/* No solution if all combinations fail */
> > > +	if(sum == 0)
> > > +		return 1;
> > > +
> > > +	/* Simple solution if all combinations pass */
> > > +	if(sum == (CAL_ROWS * CAL_COLS)) {
> > > +		*cal_row = (CAL_ROWS - 1) / 2;
> > > +		*cal_col = (CAL_COLS - 1) / 2;
> > > +		return 0;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Create list of all possible sub-rectangles, in descending area
> > > +	 * order
> > > +	 */
> > > +	for(height = CAL_ROWS; height >= 1; height--) {
> > > +		for(width = CAL_COLS; width >= 1 ; width--){
> > > +			/* Add a new rectangle candidate */
> > > +			rect_cands[cr_rect_cand].height = height;
> > > +			rect_cands[cr_rect_cand].width = width;
> > > +			rect_cands[cr_rect_cand].area = height * width;
> > > +			cr_rect_cand++;
> > > +
> > > +			/* First candidate it always in the right position */
> > > +			if(cr_rect_cand == 1)
> > > +				continue;
> > > +
> > > +			/*
> > > +			 * Put the candidate in right location to maintain
> > > +			 * descending order
> > > +			 */
> > > +			for(k = cr_rect_cand - 1; k > 1; k--){
> > > +				if(rect_cands[k-1].area < rect_cands[k].area){
> > > +					rect_cand_t tmp = rect_cands[k-1];
> > > +					rect_cands[k-1] = rect_cands[k];
> > > +					rect_cands[k] = tmp;
> > > +				} else
> > > +					break;
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	/* Try to fit the rectangle candidates, in descending area order */
> > > +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > > +		unsigned char start_row, start_col;
> > > +		unsigned rect_width = rect_cands[k].width;
> > > +		unsigned rect_height = rect_cands[k].height;
> > > +
> > > +		/* Find the row and column where the candidate fits */
> > > +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> > > +		     start_col++) {
> > > +			for (start_row = 0; start_row < (CAL_ROWS -
> > > +			     rect_height + 1); start_row++) {
> > > +				unsigned ok = 1;
> > > +				unsigned add_col, add_row;
> > > +
> > > +				/* Determine if the rectangle fits here */
> > > +				for (add_col = 0; (add_col < rect_width) && ok;
> > > +				     add_col++) {
> > > +					for (add_row = 0; add_row < rect_height;
> > > +					     add_row++) {
> > > +						if (!cal_results
> > > +						   [start_row+add_row][start_col
> > > +						   + add_col]) {
> > > +							ok = 0;
> > > +							break;
> > > +						}
> > > +					}
> > > +				}
> > > +
> > > +				/*
> > > +				 * Return 'middle' of rectangle in case of
> > > +				 * success
> > > +				 */
> > > +				if (ok) {
> > > +					if(rect_width > 1)
> > > +						rect_width--;
> > > +
> > > +					if(rect_height > 1)
> > > +						rect_height--;
> > > +
> > > +					*cal_row = start_row +
> > > +						   (rect_height / 2);
> > > +					*cal_col = start_col + (rect_width / 2);
> > > +
> > > +					return 0;
> > > +				}
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	/* We could not fit any rectangle - return failure */
> > > +	return 1;
> > 
> > Oh btw. please make sure to use errno.h and standard return codes ;
> > -EINVAL in this case I believe.
> 
> Good suggestion, will fix in v2.
> Thanks

Thanks. I was curious, is this really socfpga specific or can this calibration
be used on dwmmc in general -- thus on exynos and rockchip systems -- as well?
If it's generic to dwmmc, this should be moved into the dwmmc core code. Also,
I am CCing Simon, he's been plumbing in the DWMMC recently.

Marek Vasut

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19  8:30     ` Chin Liang See
@ 2015-08-19 23:23       ` Marek Vasut
  0 siblings, 0 replies; 40+ messages in thread
From: Marek Vasut @ 2015-08-19 23:23 UTC (permalink / raw)
  To: u-boot

On Wednesday, August 19, 2015 at 10:30:17 AM, Chin Liang See wrote:
> Him

Her

> On Wed, 2015-08-19 at 09:34 +0200, marex at denx.de wrote:
> > On Wednesday, August 19, 2015 at 09:26:55 AM, Pavel Machek wrote:
> > > On Wed 2015-08-19 00:54:50, Chin Liang See wrote:
> > > > Enable SDMMC calibration to determine the best setting for
> > > > drvsel and smpsel. It will be triggered whenever there is
> > > > a change of card frequency and bus width. This is to ensure
> > > > reliable transmission between the controller and the card.
> > > > 
> > > > Signed-off-by: Chin Liang See <clsee@altera.com>
> > > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > > > Cc: Pavel Machek <pavel@denx.de>
> > > > Cc: Marek Vasut <marex@denx.de>
> > > > Cc: Wolfgang Denk <wd@denx.de>
> > 
> > I guess there's no need to CC Wolfgang and Tom on SoCFPGA-specific stuff.
> 
> Sure, I was referring to the previous patch for the mailing list :)

No problem.

> > > > Cc: Stefan Roese <sr@denx.de>
> > > > Cc: Tom Rini <trini@konsulko.com>
> > > > ---
> > 
> > Hi!
> > 
> > > >  drivers/mmc/socfpga_dw_mmc.c |  187
> > > >  ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> > > >  insertions(+), 7 deletions(-)
> > > > 
> > > > diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > > > b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> > > > --- a/drivers/mmc/socfpga_dw_mmc.c
> > > > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > > > @@ -11,25 +11,140 @@
> > > > 
> > > >  #include <asm/arch/dwmmc.h>
> > > >  #include <asm/arch/clock_manager.h>
> > > >  #include <asm/arch/system_manager.h>
> > > > 
> > > > +#include "mmc_private.h"
> > > > 
> > > >  static const struct socfpga_clock_manager *clock_manager_base =
> > > >  
> > > >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> > > >  
> > > >  static const struct socfpga_system_manager *system_manager_base =
> > > >  
> > > >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> > > > 
> > > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > > > +#define CAL_ROWS     7
> > > > +#define CAL_COLS     8
> > 
> > What is this ugliness needed for ?
> 
> Actually this is used to create the rectangle based on the result.
> We are doing the shmoo test for the parameter smpsel and drvsel.
> 
> > btw. Please rebase on top of u-boot-socfpga/master .
> 
> Sure, just saw new changes has been added for last few hours.

I just got a few acks from Dinh, so I applied the stuff onto master. I'm
trying to keep the code up-to-date there. The repository is certainly a
bit overly active now, but that should calm down in the upcoming release.
Afterall, we got most of the nice stuff into mainline in this MW.

[...]


> > > Create separate functions to make it easier to read and less indented.
> > 
> > Right.
> 
> Let me crank my head on this :)
> Thanks

Thanks!

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-19 19:36     ` Marek Vasut
@ 2015-08-20  5:28       ` Chin Liang See
  2015-08-20  5:32         ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-08-20  5:28 UTC (permalink / raw)
  To: u-boot

Hi,

On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> > Hi,
> 
> Hi again,
> 
> > On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> > > On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> > > > Enable SDMMC calibration to determine the best setting for
> > > > drvsel and smpsel. It will be triggered whenever there is
> > > > a change of card frequency and bus width. This is to ensure
> > > > reliable transmission between the controller and the card.
> > > > 
> > > > Signed-off-by: Chin Liang See <clsee@altera.com>
> > > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > > > Cc: Pavel Machek <pavel@denx.de>
> > > > Cc: Marek Vasut <marex@denx.de>
> > > > Cc: Wolfgang Denk <wd@denx.de>
> > > > Cc: Stefan Roese <sr@denx.de>
> > > > Cc: Tom Rini <trini@konsulko.com>
> > > > ---
> > > > 
> > > >  drivers/mmc/socfpga_dw_mmc.c |  187
> > > > 
> > > > ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> > > > insertions(+), 7 deletions(-)
> > > > 
> > > > diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > > > b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> > > > --- a/drivers/mmc/socfpga_dw_mmc.c
> > > > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > > > @@ -11,25 +11,140 @@
> > > > 
> > > >  #include <asm/arch/dwmmc.h>
> > > >  #include <asm/arch/clock_manager.h>
> > > >  #include <asm/arch/system_manager.h>
> > > > 
> > > > +#include "mmc_private.h"
> > > > 
> > > >  static const struct socfpga_clock_manager *clock_manager_base =
> > > >  
> > > >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> > > >  
> > > >  static const struct socfpga_system_manager *system_manager_base =
> > > >  
> > > >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> > > > 
> > > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > > > +#define CAL_ROWS     7
> > > > +#define CAL_COLS     8
> > > > +
> > > > +/*
> > > > + * This function determines the largest rectangle filled with 1's and
> > > > returns + * the middle. This functon can be optimized, for example
> > > > using the algorithm + * from
> > > > http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
> > > > + * It currently takes less than 1ms, while creating the input data
> > > > takes ~5ms + * so there is not a real need to optimize it.
> > > > + */
> > > > +int find_calibration_point(unsigned char
> > > > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> > > > cal_row, unsigned int * cal_col)
> > > > 
> > > >  {
> > > > 
> > > > -	unsigned int drvsel;
> > > > -	unsigned int smplsel;
> > > > +	/* Structure containing a rectangle candidate */
> > > > +	typedef struct
> > > > +	{
> > > > +		unsigned char height;
> > > > +		unsigned char width;
> > > > +		unsigned short area;
> > > > +	} rect_cand_t;
> > > > +
> > > > +	/* Array with the rectangle candidates */
> > > > +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > > > +	unsigned char cr_rect_cand = 0;
> > > > +	unsigned char height, width, k;
> > > > +
> > > > +	/* No solution if all combinations fail */
> > > > +	if(sum == 0)
> > > > +		return 1;
> > > > +
> > > > +	/* Simple solution if all combinations pass */
> > > > +	if(sum == (CAL_ROWS * CAL_COLS)) {
> > > > +		*cal_row = (CAL_ROWS - 1) / 2;
> > > > +		*cal_col = (CAL_COLS - 1) / 2;
> > > > +		return 0;
> > > > +	}
> > > > +
> > > > +	/*
> > > > +	 * Create list of all possible sub-rectangles, in descending area
> > > > +	 * order
> > > > +	 */
> > > > +	for(height = CAL_ROWS; height >= 1; height--) {
> > > > +		for(width = CAL_COLS; width >= 1 ; width--){
> > > > +			/* Add a new rectangle candidate */
> > > > +			rect_cands[cr_rect_cand].height = height;
> > > > +			rect_cands[cr_rect_cand].width = width;
> > > > +			rect_cands[cr_rect_cand].area = height * width;
> > > > +			cr_rect_cand++;
> > > > +
> > > > +			/* First candidate it always in the right position */
> > > > +			if(cr_rect_cand == 1)
> > > > +				continue;
> > > > +
> > > > +			/*
> > > > +			 * Put the candidate in right location to maintain
> > > > +			 * descending order
> > > > +			 */
> > > > +			for(k = cr_rect_cand - 1; k > 1; k--){
> > > > +				if(rect_cands[k-1].area < rect_cands[k].area){
> > > > +					rect_cand_t tmp = rect_cands[k-1];
> > > > +					rect_cands[k-1] = rect_cands[k];
> > > > +					rect_cands[k] = tmp;
> > > > +				} else
> > > > +					break;
> > > > +			}
> > > > +		}
> > > > +	}
> > > > +
> > > > +	/* Try to fit the rectangle candidates, in descending area order */
> > > > +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > > > +		unsigned char start_row, start_col;
> > > > +		unsigned rect_width = rect_cands[k].width;
> > > > +		unsigned rect_height = rect_cands[k].height;
> > > > +
> > > > +		/* Find the row and column where the candidate fits */
> > > > +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 1);
> > > > +		     start_col++) {
> > > > +			for (start_row = 0; start_row < (CAL_ROWS -
> > > > +			     rect_height + 1); start_row++) {
> > > > +				unsigned ok = 1;
> > > > +				unsigned add_col, add_row;
> > > > +
> > > > +				/* Determine if the rectangle fits here */
> > > > +				for (add_col = 0; (add_col < rect_width) && ok;
> > > > +				     add_col++) {
> > > > +					for (add_row = 0; add_row < rect_height;
> > > > +					     add_row++) {
> > > > +						if (!cal_results
> > > > +						   [start_row+add_row][start_col
> > > > +						   + add_col]) {
> > > > +							ok = 0;
> > > > +							break;
> > > > +						}
> > > > +					}
> > > > +				}
> > > > +
> > > > +				/*
> > > > +				 * Return 'middle' of rectangle in case of
> > > > +				 * success
> > > > +				 */
> > > > +				if (ok) {
> > > > +					if(rect_width > 1)
> > > > +						rect_width--;
> > > > +
> > > > +					if(rect_height > 1)
> > > > +						rect_height--;
> > > > +
> > > > +					*cal_row = start_row +
> > > > +						   (rect_height / 2);
> > > > +					*cal_col = start_col + (rect_width / 2);
> > > > +
> > > > +					return 0;
> > > > +				}
> > > > +			}
> > > > +		}
> > > > +	}
> > > > +
> > > > +	/* We could not fit any rectangle - return failure */
> > > > +	return 1;
> > > 
> > > Oh btw. please make sure to use errno.h and standard return codes ;
> > > -EINVAL in this case I believe.
> > 
> > Good suggestion, will fix in v2.
> > Thanks
> 
> Thanks. I was curious, is this really socfpga specific or can this calibration
> be used on dwmmc in general -- thus on exynos and rockchip systems -- as well?
> If it's generic to dwmmc, this should be moved into the dwmmc core code. Also,
> I am CCing Simon, he's been plumbing in the DWMMC recently.
> 

I am not sure. But definitely we can make the calibration common enough
if they required the calibration too. Let wait feedback from Simon.

Chin Liang 

> Marek Vasut

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-20  5:28       ` Chin Liang See
@ 2015-08-20  5:32         ` Marek Vasut
  2015-08-20 21:55           ` Dinh Nguyen
  0 siblings, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-08-20  5:32 UTC (permalink / raw)
  To: u-boot

On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> Hi,
> 
> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> > On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> > > Hi,
> > 
> > Hi again,
> > 
> > > On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> > > > On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> > > > > Enable SDMMC calibration to determine the best setting for
> > > > > drvsel and smpsel. It will be triggered whenever there is
> > > > > a change of card frequency and bus width. This is to ensure
> > > > > reliable transmission between the controller and the card.
> > > > > 
> > > > > Signed-off-by: Chin Liang See <clsee@altera.com>
> > > > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > > > > Cc: Pavel Machek <pavel@denx.de>
> > > > > Cc: Marek Vasut <marex@denx.de>
> > > > > Cc: Wolfgang Denk <wd@denx.de>
> > > > > Cc: Stefan Roese <sr@denx.de>
> > > > > Cc: Tom Rini <trini@konsulko.com>
> > > > > ---
> > > > > 
> > > > >  drivers/mmc/socfpga_dw_mmc.c |  187
> > > > > 
> > > > > ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> > > > > insertions(+), 7 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > > > > b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> > > > > --- a/drivers/mmc/socfpga_dw_mmc.c
> > > > > +++ b/drivers/mmc/socfpga_dw_mmc.c
> > > > > @@ -11,25 +11,140 @@
> > > > > 
> > > > >  #include <asm/arch/dwmmc.h>
> > > > >  #include <asm/arch/clock_manager.h>
> > > > >  #include <asm/arch/system_manager.h>
> > > > > 
> > > > > +#include "mmc_private.h"
> > > > > 
> > > > >  static const struct socfpga_clock_manager *clock_manager_base =
> > > > >  
> > > > >  		(void *)SOCFPGA_CLKMGR_ADDRESS;
> > > > >  
> > > > >  static const struct socfpga_system_manager *system_manager_base =
> > > > >  
> > > > >  		(void *)SOCFPGA_SYSMGR_ADDRESS;
> > > > > 
> > > > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > > > > +#define CAL_ROWS     7
> > > > > +#define CAL_COLS     8
> > > > > +
> > > > > +/*
> > > > > + * This function determines the largest rectangle filled with 1's
> > > > > and returns + * the middle. This functon can be optimized, for
> > > > > example using the algorithm + * from
> > > > > http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
> > > > > 0529 + * It currently takes less than 1ms, while creating the input
> > > > > data takes ~5ms + * so there is not a real need to optimize it. +
> > > > > */
> > > > > +int find_calibration_point(unsigned char
> > > > > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> > > > > cal_row, unsigned int * cal_col)
> > > > > 
> > > > >  {
> > > > > 
> > > > > -	unsigned int drvsel;
> > > > > -	unsigned int smplsel;
> > > > > +	/* Structure containing a rectangle candidate */
> > > > > +	typedef struct
> > > > > +	{
> > > > > +		unsigned char height;
> > > > > +		unsigned char width;
> > > > > +		unsigned short area;
> > > > > +	} rect_cand_t;
> > > > > +
> > > > > +	/* Array with the rectangle candidates */
> > > > > +	rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > > > > +	unsigned char cr_rect_cand = 0;
> > > > > +	unsigned char height, width, k;
> > > > > +
> > > > > +	/* No solution if all combinations fail */
> > > > > +	if(sum == 0)
> > > > > +		return 1;
> > > > > +
> > > > > +	/* Simple solution if all combinations pass */
> > > > > +	if(sum == (CAL_ROWS * CAL_COLS)) {
> > > > > +		*cal_row = (CAL_ROWS - 1) / 2;
> > > > > +		*cal_col = (CAL_COLS - 1) / 2;
> > > > > +		return 0;
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * Create list of all possible sub-rectangles, in descending 
area
> > > > > +	 * order
> > > > > +	 */
> > > > > +	for(height = CAL_ROWS; height >= 1; height--) {
> > > > > +		for(width = CAL_COLS; width >= 1 ; width--){
> > > > > +			/* Add a new rectangle candidate */
> > > > > +			rect_cands[cr_rect_cand].height = height;
> > > > > +			rect_cands[cr_rect_cand].width = width;
> > > > > +			rect_cands[cr_rect_cand].area = height * width;
> > > > > +			cr_rect_cand++;
> > > > > +
> > > > > +			/* First candidate it always in the right 
position */
> > > > > +			if(cr_rect_cand == 1)
> > > > > +				continue;
> > > > > +
> > > > > +			/*
> > > > > +			 * Put the candidate in right location to 
maintain
> > > > > +			 * descending order
> > > > > +			 */
> > > > > +			for(k = cr_rect_cand - 1; k > 1; k--){
> > > > > +				if(rect_cands[k-1].area < 
rect_cands[k].area){
> > > > > +					rect_cand_t tmp = 
rect_cands[k-1];
> > > > > +					rect_cands[k-1] = rect_cands[k];
> > > > > +					rect_cands[k] = tmp;
> > > > > +				} else
> > > > > +					break;
> > > > > +			}
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	/* Try to fit the rectangle candidates, in descending area order
> > > > > */ +	for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > > > > +		unsigned char start_row, start_col;
> > > > > +		unsigned rect_width = rect_cands[k].width;
> > > > > +		unsigned rect_height = rect_cands[k].height;
> > > > > +
> > > > > +		/* Find the row and column where the candidate fits */
> > > > > +		for (start_col = 0; start_col < (CAL_COLS - rect_width + 
1);
> > > > > +		     start_col++) {
> > > > > +			for (start_row = 0; start_row < (CAL_ROWS -
> > > > > +			     rect_height + 1); start_row++) {
> > > > > +				unsigned ok = 1;
> > > > > +				unsigned add_col, add_row;
> > > > > +
> > > > > +				/* Determine if the rectangle fits here 
*/
> > > > > +				for (add_col = 0; (add_col < rect_width) 
&& ok;
> > > > > +				     add_col++) {
> > > > > +					for (add_row = 0; add_row < 
rect_height;
> > > > > +					     add_row++) {
> > > > > +						if (!cal_results
> > > > > +						   [start_row+add_row]
[start_col
> > > > > +						   + add_col]) {
> > > > > +							ok = 0;
> > > > > +							break;
> > > > > +						}
> > > > > +					}
> > > > > +				}
> > > > > +
> > > > > +				/*
> > > > > +				 * Return 'middle' of rectangle in case 
of
> > > > > +				 * success
> > > > > +				 */
> > > > > +				if (ok) {
> > > > > +					if(rect_width > 1)
> > > > > +						rect_width--;
> > > > > +
> > > > > +					if(rect_height > 1)
> > > > > +						rect_height--;
> > > > > +
> > > > > +					*cal_row = start_row +
> > > > > +						   (rect_height / 2);
> > > > > +					*cal_col = start_col + 
(rect_width / 2);
> > > > > +
> > > > > +					return 0;
> > > > > +				}
> > > > > +			}
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	/* We could not fit any rectangle - return failure */
> > > > > +	return 1;
> > > > 
> > > > Oh btw. please make sure to use errno.h and standard return codes ;
> > > > -EINVAL in this case I believe.
> > > 
> > > Good suggestion, will fix in v2.
> > > Thanks
> > 
> > Thanks. I was curious, is this really socfpga specific or can this
> > calibration be used on dwmmc in general -- thus on exynos and rockchip
> > systems -- as well? If it's generic to dwmmc, this should be moved into
> > the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
> > DWMMC recently.
> 
> I am not sure. But definitely we can make the calibration common enough
> if they required the calibration too. Let wait feedback from Simon.

Excellent, thanks!

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-20  5:32         ` Marek Vasut
@ 2015-08-20 21:55           ` Dinh Nguyen
  2015-08-20 21:59             ` Marek Vasut
  2015-08-21 20:52             ` Simon Glass
  0 siblings, 2 replies; 40+ messages in thread
From: Dinh Nguyen @ 2015-08-20 21:55 UTC (permalink / raw)
  To: u-boot

+CC: Simon Glass

On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
>> Hi,
>>
>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>> > On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
>> > > Hi,
>> >
>> > Hi again,
>> >
>> > > On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>> > > > On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
>> > > > > Enable SDMMC calibration to determine the best setting for
>> > > > > drvsel and smpsel. It will be triggered whenever there is
>> > > > > a change of card frequency and bus width. This is to ensure
>> > > > > reliable transmission between the controller and the card.
>> > > > >
>> > > > > Signed-off-by: Chin Liang See <clsee@altera.com>
>> > > > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>

I think there's something wrong with your git scripts, I did not get this email.

>> > > > > Cc: Pavel Machek <pavel@denx.de>
>> > > > > Cc: Marek Vasut <marex@denx.de>
>> > > > > Cc: Wolfgang Denk <wd@denx.de>
>> > > > > Cc: Stefan Roese <sr@denx.de>
>> > > > > Cc: Tom Rini <trini@konsulko.com>
>> > > > > ---
>> > > > >
>> > > > >  drivers/mmc/socfpga_dw_mmc.c |  187
>> > > > >
>> > > > > ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
>> > > > > insertions(+), 7 deletions(-)
>> > > > >
>> > > > > diff --git a/drivers/mmc/socfpga_dw_mmc.c
>> > > > > b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
>> > > > > --- a/drivers/mmc/socfpga_dw_mmc.c
>> > > > > +++ b/drivers/mmc/socfpga_dw_mmc.c
>> > > > > @@ -11,25 +11,140 @@
>> > > > >
>> > > > >  #include <asm/arch/dwmmc.h>
>> > > > >  #include <asm/arch/clock_manager.h>
>> > > > >  #include <asm/arch/system_manager.h>
>> > > > >
>> > > > > +#include "mmc_private.h"
>> > > > >
>> > > > >  static const struct socfpga_clock_manager *clock_manager_base =
>> > > > >
>> > > > >               (void *)SOCFPGA_CLKMGR_ADDRESS;
>> > > > >
>> > > > >  static const struct socfpga_system_manager *system_manager_base =
>> > > > >
>> > > > >               (void *)SOCFPGA_SYSMGR_ADDRESS;
>> > > > >
>> > > > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
>> > > > > +#define CAL_ROWS     7
>> > > > > +#define CAL_COLS     8
>> > > > > +
>> > > > > +/*
>> > > > > + * This function determines the largest rectangle filled with 1's
>> > > > > and returns + * the middle. This functon can be optimized, for
>> > > > > example using the algorithm + * from
>> > > > > http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
>> > > > > 0529 + * It currently takes less than 1ms, while creating the input
>> > > > > data takes ~5ms + * so there is not a real need to optimize it. +
>> > > > > */
>> > > > > +int find_calibration_point(unsigned char
>> > > > > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
>> > > > > cal_row, unsigned int * cal_col)
>> > > > >
>> > > > >  {
>> > > > >
>> > > > > -     unsigned int drvsel;
>> > > > > -     unsigned int smplsel;
>> > > > > +     /* Structure containing a rectangle candidate */
>> > > > > +     typedef struct
>> > > > > +     {
>> > > > > +             unsigned char height;
>> > > > > +             unsigned char width;
>> > > > > +             unsigned short area;
>> > > > > +     } rect_cand_t;
>> > > > > +
>> > > > > +     /* Array with the rectangle candidates */
>> > > > > +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
>> > > > > +     unsigned char cr_rect_cand = 0;
>> > > > > +     unsigned char height, width, k;
>> > > > > +
>> > > > > +     /* No solution if all combinations fail */
>> > > > > +     if(sum == 0)
>> > > > > +             return 1;
>> > > > > +
>> > > > > +     /* Simple solution if all combinations pass */
>> > > > > +     if(sum == (CAL_ROWS * CAL_COLS)) {
>> > > > > +             *cal_row = (CAL_ROWS - 1) / 2;
>> > > > > +             *cal_col = (CAL_COLS - 1) / 2;
>> > > > > +             return 0;
>> > > > > +     }
>> > > > > +
>> > > > > +     /*
>> > > > > +      * Create list of all possible sub-rectangles, in descending
> area
>> > > > > +      * order
>> > > > > +      */
>> > > > > +     for(height = CAL_ROWS; height >= 1; height--) {
>> > > > > +             for(width = CAL_COLS; width >= 1 ; width--){
>> > > > > +                     /* Add a new rectangle candidate */
>> > > > > +                     rect_cands[cr_rect_cand].height = height;
>> > > > > +                     rect_cands[cr_rect_cand].width = width;
>> > > > > +                     rect_cands[cr_rect_cand].area = height * width;
>> > > > > +                     cr_rect_cand++;
>> > > > > +
>> > > > > +                     /* First candidate it always in the right
> position */
>> > > > > +                     if(cr_rect_cand == 1)
>> > > > > +                             continue;
>> > > > > +
>> > > > > +                     /*
>> > > > > +                      * Put the candidate in right location to
> maintain
>> > > > > +                      * descending order
>> > > > > +                      */
>> > > > > +                     for(k = cr_rect_cand - 1; k > 1; k--){
>> > > > > +                             if(rect_cands[k-1].area <
> rect_cands[k].area){
>> > > > > +                                     rect_cand_t tmp =
> rect_cands[k-1];
>> > > > > +                                     rect_cands[k-1] = rect_cands[k];
>> > > > > +                                     rect_cands[k] = tmp;
>> > > > > +                             } else
>> > > > > +                                     break;
>> > > > > +                     }
>> > > > > +             }
>> > > > > +     }
>> > > > > +
>> > > > > +     /* Try to fit the rectangle candidates, in descending area order
>> > > > > */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
>> > > > > +             unsigned char start_row, start_col;
>> > > > > +             unsigned rect_width = rect_cands[k].width;
>> > > > > +             unsigned rect_height = rect_cands[k].height;
>> > > > > +
>> > > > > +             /* Find the row and column where the candidate fits */
>> > > > > +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
> 1);
>> > > > > +                  start_col++) {
>> > > > > +                     for (start_row = 0; start_row < (CAL_ROWS -
>> > > > > +                          rect_height + 1); start_row++) {
>> > > > > +                             unsigned ok = 1;
>> > > > > +                             unsigned add_col, add_row;
>> > > > > +
>> > > > > +                             /* Determine if the rectangle fits here
> */
>> > > > > +                             for (add_col = 0; (add_col < rect_width)
> && ok;
>> > > > > +                                  add_col++) {
>> > > > > +                                     for (add_row = 0; add_row <
> rect_height;
>> > > > > +                                          add_row++) {
>> > > > > +                                             if (!cal_results
>> > > > > +                                                [start_row+add_row]
> [start_col
>> > > > > +                                                + add_col]) {
>> > > > > +                                                     ok = 0;
>> > > > > +                                                     break;
>> > > > > +                                             }
>> > > > > +                                     }
>> > > > > +                             }
>> > > > > +
>> > > > > +                             /*
>> > > > > +                              * Return 'middle' of rectangle in case
> of
>> > > > > +                              * success
>> > > > > +                              */
>> > > > > +                             if (ok) {
>> > > > > +                                     if(rect_width > 1)
>> > > > > +                                             rect_width--;
>> > > > > +
>> > > > > +                                     if(rect_height > 1)
>> > > > > +                                             rect_height--;
>> > > > > +
>> > > > > +                                     *cal_row = start_row +
>> > > > > +                                                (rect_height / 2);
>> > > > > +                                     *cal_col = start_col +
> (rect_width / 2);
>> > > > > +
>> > > > > +                                     return 0;
>> > > > > +                             }
>> > > > > +                     }
>> > > > > +             }
>> > > > > +     }
>> > > > > +
>> > > > > +     /* We could not fit any rectangle - return failure */
>> > > > > +     return 1;
>> > > >
>> > > > Oh btw. please make sure to use errno.h and standard return codes ;
>> > > > -EINVAL in this case I believe.
>> > >
>> > > Good suggestion, will fix in v2.
>> > > Thanks
>> >
>> > Thanks. I was curious, is this really socfpga specific or can this
>> > calibration be used on dwmmc in general -- thus on exynos and rockchip
>> > systems -- as well? If it's generic to dwmmc, this should be moved into
>> > the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
>> > DWMMC recently.

I didn't see you explicitly add Simon to the thread. Doing it here..

>>
>> I am not sure. But definitely we can make the calibration common enough
>> if they required the calibration too. Let wait feedback from Simon.
>

I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
are using the drvsel and smpsel parameters. But I also think these
parameters can
be different for different types of SD card. Are you sure this
function will cover those
cases?

Dinh

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-20 21:55           ` Dinh Nguyen
@ 2015-08-20 21:59             ` Marek Vasut
  2015-08-21  0:33               ` Dinh Nguyen
  2015-08-21 20:52             ` Simon Glass
  1 sibling, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-08-20 21:59 UTC (permalink / raw)
  To: u-boot

On Thursday, August 20, 2015 at 11:55:02 PM, Dinh Nguyen wrote:
> +CC: Simon Glass

Hi Dinh,

> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> > On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> >> Hi,
> >> 
> >> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> >> > On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> >> > > Hi,
> >> > 
> >> > Hi again,
> >> > 
> >> > > On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> >> > > > On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> >> > > > > Enable SDMMC calibration to determine the best setting for
> >> > > > > drvsel and smpsel. It will be triggered whenever there is
> >> > > > > a change of card frequency and bus width. This is to ensure
> >> > > > > reliable transmission between the controller and the card.
> >> > > > > 
> >> > > > > Signed-off-by: Chin Liang See <clsee@altera.com>
> >> > > > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> 
> I think there's something wrong with your git scripts, I did not get this
> email.

You're not getting quite a lot of email I think. Could it be that altera
has some issues with their mail system after some 300 patches went through
your mailbox ? You sure you're not being filtered ? :b

> >> > > > > Cc: Pavel Machek <pavel@denx.de>
> >> > > > > Cc: Marek Vasut <marex@denx.de>
> >> > > > > Cc: Wolfgang Denk <wd@denx.de>
> >> > > > > Cc: Stefan Roese <sr@denx.de>
> >> > > > > Cc: Tom Rini <trini@konsulko.com>
> >> > > > > ---

[...]

> >> > Thanks. I was curious, is this really socfpga specific or can this
> >> > calibration be used on dwmmc in general -- thus on exynos and rockchip
> >> > systems -- as well? If it's generic to dwmmc, this should be moved
> >> > into the dwmmc core code. Also, I am CCing Simon, he's been plumbing
> >> > in the DWMMC recently.
> 
> I didn't see you explicitly add Simon to the thread. Doing it here..
> 
> >> I am not sure. But definitely we can make the calibration common enough
> >> if they required the calibration too. Let wait feedback from Simon.
> 
> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and
> Rockchip are using the drvsel and smpsel parameters. But I also think
> these parameters can
> be different for different types of SD card. Are you sure this
> function will cover those
> cases?

If we're doing the calibration, we should do it correctly :)

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-20 21:59             ` Marek Vasut
@ 2015-08-21  0:33               ` Dinh Nguyen
  2015-08-21  0:42                 ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Dinh Nguyen @ 2015-08-21  0:33 UTC (permalink / raw)
  To: u-boot



On 8/20/15 4:59 PM, Marek Vasut wrote:
> On Thursday, August 20, 2015 at 11:55:02 PM, Dinh Nguyen wrote:
>> +CC: Simon Glass
> 
> Hi Dinh,
> 
>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
>>>> Hi,
>>>>
>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
>>>>>> Hi,
>>>>>
>>>>> Hi again,
>>>>>
>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
>>>>>>>> Enable SDMMC calibration to determine the best setting for
>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
>>>>>>>> a change of card frequency and bus width. This is to ensure
>>>>>>>> reliable transmission between the controller and the card.
>>>>>>>>
>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
>>
>> I think there's something wrong with your git scripts, I did not get this
>> email.
> 
> You're not getting quite a lot of email I think. Could it be that altera
> has some issues with their mail system after some 300 patches went through
> your mailbox ? You sure you're not being filtered ? :b
> 

I would not be surprised if I was, but I don't think I am. Since I
explicitly included my email address in the CC line on my earlier
response, I am seeing the mail just fine now. My opensource.altera.com
address was not even in the cc address line at all in any of the earlier
emails.

Dinh

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-21  0:33               ` Dinh Nguyen
@ 2015-08-21  0:42                 ` Marek Vasut
  0 siblings, 0 replies; 40+ messages in thread
From: Marek Vasut @ 2015-08-21  0:42 UTC (permalink / raw)
  To: u-boot

On Friday, August 21, 2015 at 02:33:56 AM, Dinh Nguyen wrote:
> On 8/20/15 4:59 PM, Marek Vasut wrote:
> > On Thursday, August 20, 2015 at 11:55:02 PM, Dinh Nguyen wrote:
> >> +CC: Simon Glass
> > 
> > Hi Dinh,
> > 
> >> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> >>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> >>>> Hi,
> >>>> 
> >>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> >>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> >>>>>> Hi,
> >>>>> 
> >>>>> Hi again,
> >>>>> 
> >>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> >>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> >>>>>>>> Enable SDMMC calibration to determine the best setting for
> >>>>>>>> drvsel and smpsel. It will be triggered whenever there is
> >>>>>>>> a change of card frequency and bus width. This is to ensure
> >>>>>>>> reliable transmission between the controller and the card.
> >>>>>>>> 
> >>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> >>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> >> 
> >> I think there's something wrong with your git scripts, I did not get
> >> this email.
> > 
> > You're not getting quite a lot of email I think. Could it be that altera
> > has some issues with their mail system after some 300 patches went
> > through your mailbox ? You sure you're not being filtered ? :b
> 
> I would not be surprised if I was, but I don't think I am. Since I
> explicitly included my email address in the CC line on my earlier
> response, I am seeing the mail just fine now. My opensource.altera.com
> address was not even in the cc address line at all in any of the earlier
> emails.

Oh, I see, thank you for clarifying :)

Could it be that the ML itself is behaving in a funny way ? I saw this a
few times before too.

btw did you get my email about the IOCSR ?

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-20 21:55           ` Dinh Nguyen
  2015-08-20 21:59             ` Marek Vasut
@ 2015-08-21 20:52             ` Simon Glass
  2015-08-24 15:04               ` Chin Liang See
  1 sibling, 1 reply; 40+ messages in thread
From: Simon Glass @ 2015-08-21 20:52 UTC (permalink / raw)
  To: u-boot

Hi,

On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
> +CC: Simon Glass
>
> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
>>> Hi,
>>>
>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>>> > On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
>>> > > Hi,
>>> >
>>> > Hi again,
>>> >
>>> > > On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>>> > > > On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
>>> > > > > Enable SDMMC calibration to determine the best setting for
>>> > > > > drvsel and smpsel. It will be triggered whenever there is
>>> > > > > a change of card frequency and bus width. This is to ensure
>>> > > > > reliable transmission between the controller and the card.
>>> > > > >
>>> > > > > Signed-off-by: Chin Liang See <clsee@altera.com>
>>> > > > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
>
> I think there's something wrong with your git scripts, I did not get this email.
>
>>> > > > > Cc: Pavel Machek <pavel@denx.de>
>>> > > > > Cc: Marek Vasut <marex@denx.de>
>>> > > > > Cc: Wolfgang Denk <wd@denx.de>
>>> > > > > Cc: Stefan Roese <sr@denx.de>
>>> > > > > Cc: Tom Rini <trini@konsulko.com>
>>> > > > > ---
>>> > > > >
>>> > > > >  drivers/mmc/socfpga_dw_mmc.c |  187
>>> > > > >
>>> > > > > ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
>>> > > > > insertions(+), 7 deletions(-)
>>> > > > >
>>> > > > > diff --git a/drivers/mmc/socfpga_dw_mmc.c
>>> > > > > b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
>>> > > > > --- a/drivers/mmc/socfpga_dw_mmc.c
>>> > > > > +++ b/drivers/mmc/socfpga_dw_mmc.c
>>> > > > > @@ -11,25 +11,140 @@
>>> > > > >
>>> > > > >  #include <asm/arch/dwmmc.h>
>>> > > > >  #include <asm/arch/clock_manager.h>
>>> > > > >  #include <asm/arch/system_manager.h>
>>> > > > >
>>> > > > > +#include "mmc_private.h"
>>> > > > >
>>> > > > >  static const struct socfpga_clock_manager *clock_manager_base =
>>> > > > >
>>> > > > >               (void *)SOCFPGA_CLKMGR_ADDRESS;
>>> > > > >
>>> > > > >  static const struct socfpga_system_manager *system_manager_base =
>>> > > > >
>>> > > > >               (void *)SOCFPGA_SYSMGR_ADDRESS;
>>> > > > >
>>> > > > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
>>> > > > > +#define CAL_ROWS     7
>>> > > > > +#define CAL_COLS     8
>>> > > > > +
>>> > > > > +/*
>>> > > > > + * This function determines the largest rectangle filled with 1's
>>> > > > > and returns + * the middle. This functon can be optimized, for
>>> > > > > example using the algorithm + * from
>>> > > > > http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
>>> > > > > 0529 + * It currently takes less than 1ms, while creating the input
>>> > > > > data takes ~5ms + * so there is not a real need to optimize it. +
>>> > > > > */
>>> > > > > +int find_calibration_point(unsigned char
>>> > > > > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
>>> > > > > cal_row, unsigned int * cal_col)
>>> > > > >
>>> > > > >  {
>>> > > > >
>>> > > > > -     unsigned int drvsel;
>>> > > > > -     unsigned int smplsel;
>>> > > > > +     /* Structure containing a rectangle candidate */
>>> > > > > +     typedef struct
>>> > > > > +     {
>>> > > > > +             unsigned char height;
>>> > > > > +             unsigned char width;
>>> > > > > +             unsigned short area;
>>> > > > > +     } rect_cand_t;
>>> > > > > +
>>> > > > > +     /* Array with the rectangle candidates */
>>> > > > > +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
>>> > > > > +     unsigned char cr_rect_cand = 0;
>>> > > > > +     unsigned char height, width, k;
>>> > > > > +
>>> > > > > +     /* No solution if all combinations fail */
>>> > > > > +     if(sum == 0)
>>> > > > > +             return 1;
>>> > > > > +
>>> > > > > +     /* Simple solution if all combinations pass */
>>> > > > > +     if(sum == (CAL_ROWS * CAL_COLS)) {
>>> > > > > +             *cal_row = (CAL_ROWS - 1) / 2;
>>> > > > > +             *cal_col = (CAL_COLS - 1) / 2;
>>> > > > > +             return 0;
>>> > > > > +     }
>>> > > > > +
>>> > > > > +     /*
>>> > > > > +      * Create list of all possible sub-rectangles, in descending
>> area
>>> > > > > +      * order
>>> > > > > +      */
>>> > > > > +     for(height = CAL_ROWS; height >= 1; height--) {
>>> > > > > +             for(width = CAL_COLS; width >= 1 ; width--){
>>> > > > > +                     /* Add a new rectangle candidate */
>>> > > > > +                     rect_cands[cr_rect_cand].height = height;
>>> > > > > +                     rect_cands[cr_rect_cand].width = width;
>>> > > > > +                     rect_cands[cr_rect_cand].area = height * width;
>>> > > > > +                     cr_rect_cand++;
>>> > > > > +
>>> > > > > +                     /* First candidate it always in the right
>> position */
>>> > > > > +                     if(cr_rect_cand == 1)
>>> > > > > +                             continue;
>>> > > > > +
>>> > > > > +                     /*
>>> > > > > +                      * Put the candidate in right location to
>> maintain
>>> > > > > +                      * descending order
>>> > > > > +                      */
>>> > > > > +                     for(k = cr_rect_cand - 1; k > 1; k--){
>>> > > > > +                             if(rect_cands[k-1].area <
>> rect_cands[k].area){
>>> > > > > +                                     rect_cand_t tmp =
>> rect_cands[k-1];
>>> > > > > +                                     rect_cands[k-1] = rect_cands[k];
>>> > > > > +                                     rect_cands[k] = tmp;
>>> > > > > +                             } else
>>> > > > > +                                     break;
>>> > > > > +                     }
>>> > > > > +             }
>>> > > > > +     }
>>> > > > > +
>>> > > > > +     /* Try to fit the rectangle candidates, in descending area order
>>> > > > > */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
>>> > > > > +             unsigned char start_row, start_col;
>>> > > > > +             unsigned rect_width = rect_cands[k].width;
>>> > > > > +             unsigned rect_height = rect_cands[k].height;
>>> > > > > +
>>> > > > > +             /* Find the row and column where the candidate fits */
>>> > > > > +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
>> 1);
>>> > > > > +                  start_col++) {
>>> > > > > +                     for (start_row = 0; start_row < (CAL_ROWS -
>>> > > > > +                          rect_height + 1); start_row++) {
>>> > > > > +                             unsigned ok = 1;
>>> > > > > +                             unsigned add_col, add_row;
>>> > > > > +
>>> > > > > +                             /* Determine if the rectangle fits here
>> */
>>> > > > > +                             for (add_col = 0; (add_col < rect_width)
>> && ok;
>>> > > > > +                                  add_col++) {
>>> > > > > +                                     for (add_row = 0; add_row <
>> rect_height;
>>> > > > > +                                          add_row++) {
>>> > > > > +                                             if (!cal_results
>>> > > > > +                                                [start_row+add_row]
>> [start_col
>>> > > > > +                                                + add_col]) {
>>> > > > > +                                                     ok = 0;
>>> > > > > +                                                     break;
>>> > > > > +                                             }
>>> > > > > +                                     }
>>> > > > > +                             }
>>> > > > > +
>>> > > > > +                             /*
>>> > > > > +                              * Return 'middle' of rectangle in case
>> of
>>> > > > > +                              * success
>>> > > > > +                              */
>>> > > > > +                             if (ok) {
>>> > > > > +                                     if(rect_width > 1)
>>> > > > > +                                             rect_width--;
>>> > > > > +
>>> > > > > +                                     if(rect_height > 1)
>>> > > > > +                                             rect_height--;
>>> > > > > +
>>> > > > > +                                     *cal_row = start_row +
>>> > > > > +                                                (rect_height / 2);
>>> > > > > +                                     *cal_col = start_col +
>> (rect_width / 2);
>>> > > > > +
>>> > > > > +                                     return 0;
>>> > > > > +                             }
>>> > > > > +                     }
>>> > > > > +             }
>>> > > > > +     }
>>> > > > > +
>>> > > > > +     /* We could not fit any rectangle - return failure */
>>> > > > > +     return 1;
>>> > > >
>>> > > > Oh btw. please make sure to use errno.h and standard return codes ;
>>> > > > -EINVAL in this case I believe.
>>> > >
>>> > > Good suggestion, will fix in v2.
>>> > > Thanks
>>> >
>>> > Thanks. I was curious, is this really socfpga specific or can this
>>> > calibration be used on dwmmc in general -- thus on exynos and rockchip
>>> > systems -- as well? If it's generic to dwmmc, this should be moved into
>>> > the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
>>> > DWMMC recently.
>
> I didn't see you explicitly add Simon to the thread. Doing it here..

One option is to put the function in the common dw_mmc.c file but have
it be called explicitly by drivers that want it (e.g. for now, just
socfpga). The code you have written does look generic and perhaps
should be used on other platforms,

>
>>>
>>> I am not sure. But definitely we can make the calibration common enough
>>> if they required the calibration too. Let wait feedback from Simon.
>>
>
> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
> are using the drvsel and smpsel parameters. But I also think these
> parameters can
> be different for different types of SD card. Are you sure this
> function will cover those
> cases?

Not at all, but perhaps that is something we will find out in the future.

Regards,
Simon

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-21 20:52             ` Simon Glass
@ 2015-08-24 15:04               ` Chin Liang See
  2015-08-25  2:36                 ` Jaehoon Chung
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-08-24 15:04 UTC (permalink / raw)
  To: u-boot

On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> Hi,
> 
> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
> > +CC: Simon Glass
> >
> > On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> >> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> >>> Hi,
> >>>
> >>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> >>> > On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> >>> > > Hi,
> >>> >
> >>> > Hi again,
> >>> >
> >>> > > On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> >>> > > > On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> >>> > > > > Enable SDMMC calibration to determine the best setting for
> >>> > > > > drvsel and smpsel. It will be triggered whenever there is
> >>> > > > > a change of card frequency and bus width. This is to ensure
> >>> > > > > reliable transmission between the controller and the card.
> >>> > > > >
> >>> > > > > Signed-off-by: Chin Liang See <clsee@altera.com>
> >>> > > > > Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> >
> > I think there's something wrong with your git scripts, I did not get this email.
> >
> >>> > > > > Cc: Pavel Machek <pavel@denx.de>
> >>> > > > > Cc: Marek Vasut <marex@denx.de>
> >>> > > > > Cc: Wolfgang Denk <wd@denx.de>
> >>> > > > > Cc: Stefan Roese <sr@denx.de>
> >>> > > > > Cc: Tom Rini <trini@konsulko.com>
> >>> > > > > ---
> >>> > > > >
> >>> > > > >  drivers/mmc/socfpga_dw_mmc.c |  187
> >>> > > > >
> >>> > > > > ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> >>> > > > > insertions(+), 7 deletions(-)
> >>> > > > >
> >>> > > > > diff --git a/drivers/mmc/socfpga_dw_mmc.c
> >>> > > > > b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> >>> > > > > --- a/drivers/mmc/socfpga_dw_mmc.c
> >>> > > > > +++ b/drivers/mmc/socfpga_dw_mmc.c
> >>> > > > > @@ -11,25 +11,140 @@
> >>> > > > >
> >>> > > > >  #include <asm/arch/dwmmc.h>
> >>> > > > >  #include <asm/arch/clock_manager.h>
> >>> > > > >  #include <asm/arch/system_manager.h>
> >>> > > > >
> >>> > > > > +#include "mmc_private.h"
> >>> > > > >
> >>> > > > >  static const struct socfpga_clock_manager *clock_manager_base =
> >>> > > > >
> >>> > > > >               (void *)SOCFPGA_CLKMGR_ADDRESS;
> >>> > > > >
> >>> > > > >  static const struct socfpga_system_manager *system_manager_base =
> >>> > > > >
> >>> > > > >               (void *)SOCFPGA_SYSMGR_ADDRESS;
> >>> > > > >
> >>> > > > > -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> >>> > > > > +#define CAL_ROWS     7
> >>> > > > > +#define CAL_COLS     8
> >>> > > > > +
> >>> > > > > +/*
> >>> > > > > + * This function determines the largest rectangle filled with 1's
> >>> > > > > and returns + * the middle. This functon can be optimized, for
> >>> > > > > example using the algorithm + * from
> >>> > > > > http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
> >>> > > > > 0529 + * It currently takes less than 1ms, while creating the input
> >>> > > > > data takes ~5ms + * so there is not a real need to optimize it. +
> >>> > > > > */
> >>> > > > > +int find_calibration_point(unsigned char
> >>> > > > > cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> >>> > > > > cal_row, unsigned int * cal_col)
> >>> > > > >
> >>> > > > >  {
> >>> > > > >
> >>> > > > > -     unsigned int drvsel;
> >>> > > > > -     unsigned int smplsel;
> >>> > > > > +     /* Structure containing a rectangle candidate */
> >>> > > > > +     typedef struct
> >>> > > > > +     {
> >>> > > > > +             unsigned char height;
> >>> > > > > +             unsigned char width;
> >>> > > > > +             unsigned short area;
> >>> > > > > +     } rect_cand_t;
> >>> > > > > +
> >>> > > > > +     /* Array with the rectangle candidates */
> >>> > > > > +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> >>> > > > > +     unsigned char cr_rect_cand = 0;
> >>> > > > > +     unsigned char height, width, k;
> >>> > > > > +
> >>> > > > > +     /* No solution if all combinations fail */
> >>> > > > > +     if(sum == 0)
> >>> > > > > +             return 1;
> >>> > > > > +
> >>> > > > > +     /* Simple solution if all combinations pass */
> >>> > > > > +     if(sum == (CAL_ROWS * CAL_COLS)) {
> >>> > > > > +             *cal_row = (CAL_ROWS - 1) / 2;
> >>> > > > > +             *cal_col = (CAL_COLS - 1) / 2;
> >>> > > > > +             return 0;
> >>> > > > > +     }
> >>> > > > > +
> >>> > > > > +     /*
> >>> > > > > +      * Create list of all possible sub-rectangles, in descending
> >> area
> >>> > > > > +      * order
> >>> > > > > +      */
> >>> > > > > +     for(height = CAL_ROWS; height >= 1; height--) {
> >>> > > > > +             for(width = CAL_COLS; width >= 1 ; width--){
> >>> > > > > +                     /* Add a new rectangle candidate */
> >>> > > > > +                     rect_cands[cr_rect_cand].height = height;
> >>> > > > > +                     rect_cands[cr_rect_cand].width = width;
> >>> > > > > +                     rect_cands[cr_rect_cand].area = height * width;
> >>> > > > > +                     cr_rect_cand++;
> >>> > > > > +
> >>> > > > > +                     /* First candidate it always in the right
> >> position */
> >>> > > > > +                     if(cr_rect_cand == 1)
> >>> > > > > +                             continue;
> >>> > > > > +
> >>> > > > > +                     /*
> >>> > > > > +                      * Put the candidate in right location to
> >> maintain
> >>> > > > > +                      * descending order
> >>> > > > > +                      */
> >>> > > > > +                     for(k = cr_rect_cand - 1; k > 1; k--){
> >>> > > > > +                             if(rect_cands[k-1].area <
> >> rect_cands[k].area){
> >>> > > > > +                                     rect_cand_t tmp =
> >> rect_cands[k-1];
> >>> > > > > +                                     rect_cands[k-1] = rect_cands[k];
> >>> > > > > +                                     rect_cands[k] = tmp;
> >>> > > > > +                             } else
> >>> > > > > +                                     break;
> >>> > > > > +                     }
> >>> > > > > +             }
> >>> > > > > +     }
> >>> > > > > +
> >>> > > > > +     /* Try to fit the rectangle candidates, in descending area order
> >>> > > > > */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> >>> > > > > +             unsigned char start_row, start_col;
> >>> > > > > +             unsigned rect_width = rect_cands[k].width;
> >>> > > > > +             unsigned rect_height = rect_cands[k].height;
> >>> > > > > +
> >>> > > > > +             /* Find the row and column where the candidate fits */
> >>> > > > > +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
> >> 1);
> >>> > > > > +                  start_col++) {
> >>> > > > > +                     for (start_row = 0; start_row < (CAL_ROWS -
> >>> > > > > +                          rect_height + 1); start_row++) {
> >>> > > > > +                             unsigned ok = 1;
> >>> > > > > +                             unsigned add_col, add_row;
> >>> > > > > +
> >>> > > > > +                             /* Determine if the rectangle fits here
> >> */
> >>> > > > > +                             for (add_col = 0; (add_col < rect_width)
> >> && ok;
> >>> > > > > +                                  add_col++) {
> >>> > > > > +                                     for (add_row = 0; add_row <
> >> rect_height;
> >>> > > > > +                                          add_row++) {
> >>> > > > > +                                             if (!cal_results
> >>> > > > > +                                                [start_row+add_row]
> >> [start_col
> >>> > > > > +                                                + add_col]) {
> >>> > > > > +                                                     ok = 0;
> >>> > > > > +                                                     break;
> >>> > > > > +                                             }
> >>> > > > > +                                     }
> >>> > > > > +                             }
> >>> > > > > +
> >>> > > > > +                             /*
> >>> > > > > +                              * Return 'middle' of rectangle in case
> >> of
> >>> > > > > +                              * success
> >>> > > > > +                              */
> >>> > > > > +                             if (ok) {
> >>> > > > > +                                     if(rect_width > 1)
> >>> > > > > +                                             rect_width--;
> >>> > > > > +
> >>> > > > > +                                     if(rect_height > 1)
> >>> > > > > +                                             rect_height--;
> >>> > > > > +
> >>> > > > > +                                     *cal_row = start_row +
> >>> > > > > +                                                (rect_height / 2);
> >>> > > > > +                                     *cal_col = start_col +
> >> (rect_width / 2);
> >>> > > > > +
> >>> > > > > +                                     return 0;
> >>> > > > > +                             }
> >>> > > > > +                     }
> >>> > > > > +             }
> >>> > > > > +     }
> >>> > > > > +
> >>> > > > > +     /* We could not fit any rectangle - return failure */
> >>> > > > > +     return 1;
> >>> > > >
> >>> > > > Oh btw. please make sure to use errno.h and standard return codes ;
> >>> > > > -EINVAL in this case I believe.
> >>> > >
> >>> > > Good suggestion, will fix in v2.
> >>> > > Thanks
> >>> >
> >>> > Thanks. I was curious, is this really socfpga specific or can this
> >>> > calibration be used on dwmmc in general -- thus on exynos and rockchip
> >>> > systems -- as well? If it's generic to dwmmc, this should be moved into
> >>> > the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
> >>> > DWMMC recently.
> >
> > I didn't see you explicitly add Simon to the thread. Doing it here..
> 
> One option is to put the function in the common dw_mmc.c file but have
> it be called explicitly by drivers that want it (e.g. for now, just
> socfpga). The code you have written does look generic and perhaps
> should be used on other platforms,
> 
> >
> >>>
> >>> I am not sure. But definitely we can make the calibration common enough
> >>> if they required the calibration too. Let wait feedback from Simon.
> >>
> >
> > I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
> > are using the drvsel and smpsel parameters. But I also think these
> > parameters can
> > be different for different types of SD card. Are you sure this
> > function will cover those
> > cases?
> 
> Not at all, but perhaps that is something we will find out in the future.
> 

Thanks Simon.

I further checked today and noticed Exynos is setting up the clksel
(sample clock and drive clock). But from exynos_dw_mmc.c, the value is
coming from device tree. So I am notifying Jaehoon wonder the
calibration might applicable for him. 

Jaehoon, this patch will do a calibration to determine the clksel value.
Wonder is this something would help or applicable for Exynos? We are
probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.

Thanks
Chin Liang

> Regards,
> Simon

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-24 15:04               ` Chin Liang See
@ 2015-08-25  2:36                 ` Jaehoon Chung
  2015-08-25  3:08                   ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Jaehoon Chung @ 2015-08-25  2:36 UTC (permalink / raw)
  To: u-boot

Hi,

On 08/25/2015 12:04 AM, Chin Liang See wrote:
> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
>> Hi,
>>
>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
>>> +CC: Simon Glass
>>>
>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
>>>>> Hi,
>>>>>
>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
>>>>>>> Hi,
>>>>>>
>>>>>> Hi again,
>>>>>>
>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
>>>>>>>>> Enable SDMMC calibration to determine the best setting for
>>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
>>>>>>>>> a change of card frequency and bus width. This is to ensure
>>>>>>>>> reliable transmission between the controller and the card.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
>>>
>>> I think there's something wrong with your git scripts, I did not get this email.
>>>
>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
>>>>>>>>> ---
>>>>>>>>>
>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
>>>>>>>>>
>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
>>>>>>>>> insertions(+), 7 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
>>>>>>>>> --- a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>> @@ -11,25 +11,140 @@
>>>>>>>>>
>>>>>>>>>  #include <asm/arch/dwmmc.h>
>>>>>>>>>  #include <asm/arch/clock_manager.h>
>>>>>>>>>  #include <asm/arch/system_manager.h>
>>>>>>>>>
>>>>>>>>> +#include "mmc_private.h"
>>>>>>>>>
>>>>>>>>>  static const struct socfpga_clock_manager *clock_manager_base =
>>>>>>>>>
>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
>>>>>>>>>
>>>>>>>>>  static const struct socfpga_system_manager *system_manager_base =
>>>>>>>>>
>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
>>>>>>>>>
>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
>>>>>>>>> +#define CAL_ROWS     7
>>>>>>>>> +#define CAL_COLS     8
>>>>>>>>> +
>>>>>>>>> +/*
>>>>>>>>> + * This function determines the largest rectangle filled with 1's
>>>>>>>>> and returns + * the middle. This functon can be optimized, for
>>>>>>>>> example using the algorithm + * from
>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
>>>>>>>>> 0529 + * It currently takes less than 1ms, while creating the input
>>>>>>>>> data takes ~5ms + * so there is not a real need to optimize it. +
>>>>>>>>> */
>>>>>>>>> +int find_calibration_point(unsigned char
>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
>>>>>>>>> cal_row, unsigned int * cal_col)
>>>>>>>>>
>>>>>>>>>  {
>>>>>>>>>
>>>>>>>>> -     unsigned int drvsel;
>>>>>>>>> -     unsigned int smplsel;
>>>>>>>>> +     /* Structure containing a rectangle candidate */
>>>>>>>>> +     typedef struct
>>>>>>>>> +     {
>>>>>>>>> +             unsigned char height;
>>>>>>>>> +             unsigned char width;
>>>>>>>>> +             unsigned short area;
>>>>>>>>> +     } rect_cand_t;
>>>>>>>>> +
>>>>>>>>> +     /* Array with the rectangle candidates */
>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
>>>>>>>>> +     unsigned char cr_rect_cand = 0;
>>>>>>>>> +     unsigned char height, width, k;
>>>>>>>>> +
>>>>>>>>> +     /* No solution if all combinations fail */
>>>>>>>>> +     if(sum == 0)
>>>>>>>>> +             return 1;
>>>>>>>>> +
>>>>>>>>> +     /* Simple solution if all combinations pass */
>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
>>>>>>>>> +             return 0;
>>>>>>>>> +     }
>>>>>>>>> +
>>>>>>>>> +     /*
>>>>>>>>> +      * Create list of all possible sub-rectangles, in descending
>>>> area
>>>>>>>>> +      * order
>>>>>>>>> +      */
>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ; width--){
>>>>>>>>> +                     /* Add a new rectangle candidate */
>>>>>>>>> +                     rect_cands[cr_rect_cand].height = height;
>>>>>>>>> +                     rect_cands[cr_rect_cand].width = width;
>>>>>>>>> +                     rect_cands[cr_rect_cand].area = height * width;
>>>>>>>>> +                     cr_rect_cand++;
>>>>>>>>> +
>>>>>>>>> +                     /* First candidate it always in the right
>>>> position */
>>>>>>>>> +                     if(cr_rect_cand == 1)
>>>>>>>>> +                             continue;
>>>>>>>>> +
>>>>>>>>> +                     /*
>>>>>>>>> +                      * Put the candidate in right location to
>>>> maintain
>>>>>>>>> +                      * descending order
>>>>>>>>> +                      */
>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1; k--){
>>>>>>>>> +                             if(rect_cands[k-1].area <
>>>> rect_cands[k].area){
>>>>>>>>> +                                     rect_cand_t tmp =
>>>> rect_cands[k-1];
>>>>>>>>> +                                     rect_cands[k-1] = rect_cands[k];
>>>>>>>>> +                                     rect_cands[k] = tmp;
>>>>>>>>> +                             } else
>>>>>>>>> +                                     break;
>>>>>>>>> +                     }
>>>>>>>>> +             }
>>>>>>>>> +     }
>>>>>>>>> +
>>>>>>>>> +     /* Try to fit the rectangle candidates, in descending area order
>>>>>>>>> */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
>>>>>>>>> +             unsigned char start_row, start_col;
>>>>>>>>> +             unsigned rect_width = rect_cands[k].width;
>>>>>>>>> +             unsigned rect_height = rect_cands[k].height;
>>>>>>>>> +
>>>>>>>>> +             /* Find the row and column where the candidate fits */
>>>>>>>>> +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
>>>> 1);
>>>>>>>>> +                  start_col++) {
>>>>>>>>> +                     for (start_row = 0; start_row < (CAL_ROWS -
>>>>>>>>> +                          rect_height + 1); start_row++) {
>>>>>>>>> +                             unsigned ok = 1;
>>>>>>>>> +                             unsigned add_col, add_row;
>>>>>>>>> +
>>>>>>>>> +                             /* Determine if the rectangle fits here
>>>> */
>>>>>>>>> +                             for (add_col = 0; (add_col < rect_width)
>>>> && ok;
>>>>>>>>> +                                  add_col++) {
>>>>>>>>> +                                     for (add_row = 0; add_row <
>>>> rect_height;
>>>>>>>>> +                                          add_row++) {
>>>>>>>>> +                                             if (!cal_results
>>>>>>>>> +                                                [start_row+add_row]
>>>> [start_col
>>>>>>>>> +                                                + add_col]) {
>>>>>>>>> +                                                     ok = 0;
>>>>>>>>> +                                                     break;
>>>>>>>>> +                                             }
>>>>>>>>> +                                     }
>>>>>>>>> +                             }
>>>>>>>>> +
>>>>>>>>> +                             /*
>>>>>>>>> +                              * Return 'middle' of rectangle in case
>>>> of
>>>>>>>>> +                              * success
>>>>>>>>> +                              */
>>>>>>>>> +                             if (ok) {
>>>>>>>>> +                                     if(rect_width > 1)
>>>>>>>>> +                                             rect_width--;
>>>>>>>>> +
>>>>>>>>> +                                     if(rect_height > 1)
>>>>>>>>> +                                             rect_height--;
>>>>>>>>> +
>>>>>>>>> +                                     *cal_row = start_row +
>>>>>>>>> +                                                (rect_height / 2);
>>>>>>>>> +                                     *cal_col = start_col +
>>>> (rect_width / 2);
>>>>>>>>> +
>>>>>>>>> +                                     return 0;
>>>>>>>>> +                             }
>>>>>>>>> +                     }
>>>>>>>>> +             }
>>>>>>>>> +     }
>>>>>>>>> +
>>>>>>>>> +     /* We could not fit any rectangle - return failure */
>>>>>>>>> +     return 1;
>>>>>>>>
>>>>>>>> Oh btw. please make sure to use errno.h and standard return codes ;
>>>>>>>> -EINVAL in this case I believe.
>>>>>>>
>>>>>>> Good suggestion, will fix in v2.
>>>>>>> Thanks
>>>>>>
>>>>>> Thanks. I was curious, is this really socfpga specific or can this
>>>>>> calibration be used on dwmmc in general -- thus on exynos and rockchip
>>>>>> systems -- as well? If it's generic to dwmmc, this should be moved into
>>>>>> the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
>>>>>> DWMMC recently.
>>>
>>> I didn't see you explicitly add Simon to the thread. Doing it here..
>>
>> One option is to put the function in the common dw_mmc.c file but have
>> it be called explicitly by drivers that want it (e.g. for now, just
>> socfpga). The code you have written does look generic and perhaps
>> should be used on other platforms,
>>
>>>
>>>>>
>>>>> I am not sure. But definitely we can make the calibration common enough
>>>>> if they required the calibration too. Let wait feedback from Simon.
>>>>
>>>
>>> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
>>> are using the drvsel and smpsel parameters. But I also think these
>>> parameters can
>>> be different for different types of SD card. Are you sure this
>>> function will cover those
>>> cases?
>>
>> Not at all, but perhaps that is something we will find out in the future.
>>
> 
> Thanks Simon.
> 
> I further checked today and noticed Exynos is setting up the clksel
> (sample clock and drive clock). But from exynos_dw_mmc.c, the value is
> coming from device tree. So I am notifying Jaehoon wonder the
> calibration might applicable for him. 

Thanks for notifying this. But I can't find this patch at patchwork.
I'm not reading fully mail thread, so after reading mails, i will resend at mailing list.

Best Regards,
Jaehoon Chung

> 
> Jaehoon, this patch will do a calibration to determine the clksel value.
> Wonder is this something would help or applicable for Exynos? We are
> probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.
> 
> Thanks
> Chin Liang
> 
>> Regards,
>> Simon
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-25  2:36                 ` Jaehoon Chung
@ 2015-08-25  3:08                   ` Chin Liang See
  2015-08-26  5:29                     ` Jaehoon Chung
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-08-25  3:08 UTC (permalink / raw)
  To: u-boot

On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> Hi,
> 
> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> > On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> >> Hi,
> >>
> >> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
> >>> +CC: Simon Glass
> >>>
> >>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> >>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> >>>>> Hi,
> >>>>>
> >>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> >>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> >>>>>>> Hi,
> >>>>>>
> >>>>>> Hi again,
> >>>>>>
> >>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> >>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> >>>>>>>>> Enable SDMMC calibration to determine the best setting for
> >>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
> >>>>>>>>> a change of card frequency and bus width. This is to ensure
> >>>>>>>>> reliable transmission between the controller and the card.
> >>>>>>>>>
> >>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> >>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> >>>
> >>> I think there's something wrong with your git scripts, I did not get this email.
> >>>
> >>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> >>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> >>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> >>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> >>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> >>>>>>>>> ---
> >>>>>>>>>
> >>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> >>>>>>>>>
> >>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> >>>>>>>>> insertions(+), 7 deletions(-)
> >>>>>>>>>
> >>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> >>>>>>>>> --- a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>> @@ -11,25 +11,140 @@
> >>>>>>>>>
> >>>>>>>>>  #include <asm/arch/dwmmc.h>
> >>>>>>>>>  #include <asm/arch/clock_manager.h>
> >>>>>>>>>  #include <asm/arch/system_manager.h>
> >>>>>>>>>
> >>>>>>>>> +#include "mmc_private.h"
> >>>>>>>>>
> >>>>>>>>>  static const struct socfpga_clock_manager *clock_manager_base =
> >>>>>>>>>
> >>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> >>>>>>>>>
> >>>>>>>>>  static const struct socfpga_system_manager *system_manager_base =
> >>>>>>>>>
> >>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> >>>>>>>>>
> >>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> >>>>>>>>> +#define CAL_ROWS     7
> >>>>>>>>> +#define CAL_COLS     8
> >>>>>>>>> +
> >>>>>>>>> +/*
> >>>>>>>>> + * This function determines the largest rectangle filled with 1's
> >>>>>>>>> and returns + * the middle. This functon can be optimized, for
> >>>>>>>>> example using the algorithm + * from
> >>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
> >>>>>>>>> 0529 + * It currently takes less than 1ms, while creating the input
> >>>>>>>>> data takes ~5ms + * so there is not a real need to optimize it. +
> >>>>>>>>> */
> >>>>>>>>> +int find_calibration_point(unsigned char
> >>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> >>>>>>>>> cal_row, unsigned int * cal_col)
> >>>>>>>>>
> >>>>>>>>>  {
> >>>>>>>>>
> >>>>>>>>> -     unsigned int drvsel;
> >>>>>>>>> -     unsigned int smplsel;
> >>>>>>>>> +     /* Structure containing a rectangle candidate */
> >>>>>>>>> +     typedef struct
> >>>>>>>>> +     {
> >>>>>>>>> +             unsigned char height;
> >>>>>>>>> +             unsigned char width;
> >>>>>>>>> +             unsigned short area;
> >>>>>>>>> +     } rect_cand_t;
> >>>>>>>>> +
> >>>>>>>>> +     /* Array with the rectangle candidates */
> >>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> >>>>>>>>> +     unsigned char cr_rect_cand = 0;
> >>>>>>>>> +     unsigned char height, width, k;
> >>>>>>>>> +
> >>>>>>>>> +     /* No solution if all combinations fail */
> >>>>>>>>> +     if(sum == 0)
> >>>>>>>>> +             return 1;
> >>>>>>>>> +
> >>>>>>>>> +     /* Simple solution if all combinations pass */
> >>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> >>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> >>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> >>>>>>>>> +             return 0;
> >>>>>>>>> +     }
> >>>>>>>>> +
> >>>>>>>>> +     /*
> >>>>>>>>> +      * Create list of all possible sub-rectangles, in descending
> >>>> area
> >>>>>>>>> +      * order
> >>>>>>>>> +      */
> >>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> >>>>>>>>> +             for(width = CAL_COLS; width >= 1 ; width--){
> >>>>>>>>> +                     /* Add a new rectangle candidate */
> >>>>>>>>> +                     rect_cands[cr_rect_cand].height = height;
> >>>>>>>>> +                     rect_cands[cr_rect_cand].width = width;
> >>>>>>>>> +                     rect_cands[cr_rect_cand].area = height * width;
> >>>>>>>>> +                     cr_rect_cand++;
> >>>>>>>>> +
> >>>>>>>>> +                     /* First candidate it always in the right
> >>>> position */
> >>>>>>>>> +                     if(cr_rect_cand == 1)
> >>>>>>>>> +                             continue;
> >>>>>>>>> +
> >>>>>>>>> +                     /*
> >>>>>>>>> +                      * Put the candidate in right location to
> >>>> maintain
> >>>>>>>>> +                      * descending order
> >>>>>>>>> +                      */
> >>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1; k--){
> >>>>>>>>> +                             if(rect_cands[k-1].area <
> >>>> rect_cands[k].area){
> >>>>>>>>> +                                     rect_cand_t tmp =
> >>>> rect_cands[k-1];
> >>>>>>>>> +                                     rect_cands[k-1] = rect_cands[k];
> >>>>>>>>> +                                     rect_cands[k] = tmp;
> >>>>>>>>> +                             } else
> >>>>>>>>> +                                     break;
> >>>>>>>>> +                     }
> >>>>>>>>> +             }
> >>>>>>>>> +     }
> >>>>>>>>> +
> >>>>>>>>> +     /* Try to fit the rectangle candidates, in descending area order
> >>>>>>>>> */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> >>>>>>>>> +             unsigned char start_row, start_col;
> >>>>>>>>> +             unsigned rect_width = rect_cands[k].width;
> >>>>>>>>> +             unsigned rect_height = rect_cands[k].height;
> >>>>>>>>> +
> >>>>>>>>> +             /* Find the row and column where the candidate fits */
> >>>>>>>>> +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
> >>>> 1);
> >>>>>>>>> +                  start_col++) {
> >>>>>>>>> +                     for (start_row = 0; start_row < (CAL_ROWS -
> >>>>>>>>> +                          rect_height + 1); start_row++) {
> >>>>>>>>> +                             unsigned ok = 1;
> >>>>>>>>> +                             unsigned add_col, add_row;
> >>>>>>>>> +
> >>>>>>>>> +                             /* Determine if the rectangle fits here
> >>>> */
> >>>>>>>>> +                             for (add_col = 0; (add_col < rect_width)
> >>>> && ok;
> >>>>>>>>> +                                  add_col++) {
> >>>>>>>>> +                                     for (add_row = 0; add_row <
> >>>> rect_height;
> >>>>>>>>> +                                          add_row++) {
> >>>>>>>>> +                                             if (!cal_results
> >>>>>>>>> +                                                [start_row+add_row]
> >>>> [start_col
> >>>>>>>>> +                                                + add_col]) {
> >>>>>>>>> +                                                     ok = 0;
> >>>>>>>>> +                                                     break;
> >>>>>>>>> +                                             }
> >>>>>>>>> +                                     }
> >>>>>>>>> +                             }
> >>>>>>>>> +
> >>>>>>>>> +                             /*
> >>>>>>>>> +                              * Return 'middle' of rectangle in case
> >>>> of
> >>>>>>>>> +                              * success
> >>>>>>>>> +                              */
> >>>>>>>>> +                             if (ok) {
> >>>>>>>>> +                                     if(rect_width > 1)
> >>>>>>>>> +                                             rect_width--;
> >>>>>>>>> +
> >>>>>>>>> +                                     if(rect_height > 1)
> >>>>>>>>> +                                             rect_height--;
> >>>>>>>>> +
> >>>>>>>>> +                                     *cal_row = start_row +
> >>>>>>>>> +                                                (rect_height / 2);
> >>>>>>>>> +                                     *cal_col = start_col +
> >>>> (rect_width / 2);
> >>>>>>>>> +
> >>>>>>>>> +                                     return 0;
> >>>>>>>>> +                             }
> >>>>>>>>> +                     }
> >>>>>>>>> +             }
> >>>>>>>>> +     }
> >>>>>>>>> +
> >>>>>>>>> +     /* We could not fit any rectangle - return failure */
> >>>>>>>>> +     return 1;
> >>>>>>>>
> >>>>>>>> Oh btw. please make sure to use errno.h and standard return codes ;
> >>>>>>>> -EINVAL in this case I believe.
> >>>>>>>
> >>>>>>> Good suggestion, will fix in v2.
> >>>>>>> Thanks
> >>>>>>
> >>>>>> Thanks. I was curious, is this really socfpga specific or can this
> >>>>>> calibration be used on dwmmc in general -- thus on exynos and rockchip
> >>>>>> systems -- as well? If it's generic to dwmmc, this should be moved into
> >>>>>> the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
> >>>>>> DWMMC recently.
> >>>
> >>> I didn't see you explicitly add Simon to the thread. Doing it here..
> >>
> >> One option is to put the function in the common dw_mmc.c file but have
> >> it be called explicitly by drivers that want it (e.g. for now, just
> >> socfpga). The code you have written does look generic and perhaps
> >> should be used on other platforms,
> >>
> >>>
> >>>>>
> >>>>> I am not sure. But definitely we can make the calibration common enough
> >>>>> if they required the calibration too. Let wait feedback from Simon.
> >>>>
> >>>
> >>> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
> >>> are using the drvsel and smpsel parameters. But I also think these
> >>> parameters can
> >>> be different for different types of SD card. Are you sure this
> >>> function will cover those
> >>> cases?
> >>
> >> Not at all, but perhaps that is something we will find out in the future.
> >>
> > 
> > Thanks Simon.
> > 
> > I further checked today and noticed Exynos is setting up the clksel
> > (sample clock and drive clock). But from exynos_dw_mmc.c, the value is
> > coming from device tree. So I am notifying Jaehoon wonder the
> > calibration might applicable for him. 
> 
> Thanks for notifying this. But I can't find this patch at patchwork.
> I'm not reading fully mail thread, so after reading mails, i will resend at mailing list.

Sure, here is the link :)
http://lists.denx.de/pipermail/u-boot/2015-August/224566.html

Thanks
Chin Liang


> 
> Best Regards,
> Jaehoon Chung
> 
> > 
> > Jaehoon, this patch will do a calibration to determine the clksel value.
> > Wonder is this something would help or applicable for Exynos? We are
> > probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.
> > 
> > Thanks
> > Chin Liang
> > 
> >> Regards,
> >> Simon
> > 
> > 
> > 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-25  3:08                   ` Chin Liang See
@ 2015-08-26  5:29                     ` Jaehoon Chung
  2015-08-26  5:47                       ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Jaehoon Chung @ 2015-08-26  5:29 UTC (permalink / raw)
  To: u-boot

Hi,

On 08/25/2015 12:08 PM, Chin Liang See wrote:
> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
>> Hi,
>>
>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
>>>> Hi,
>>>>
>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
>>>>> +CC: Simon Glass
>>>>>
>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
>>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Hi again,
>>>>>>>>
>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
>>>>>>>>>>> Enable SDMMC calibration to determine the best setting for
>>>>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
>>>>>>>>>>> a change of card frequency and bus width. This is to ensure
>>>>>>>>>>> reliable transmission between the controller and the card.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
>>>>>
>>>>> I think there's something wrong with your git scripts, I did not get this email.
>>>>>
>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
>>>>>>>>>>> ---
>>>>>>>>>>>
>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
>>>>>>>>>>>
>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
>>>>>>>>>>> insertions(+), 7 deletions(-)
>>>>>>>>>>>
>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
>>>>>>>>>>> --- a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>> @@ -11,25 +11,140 @@
>>>>>>>>>>>
>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
>>>>>>>>>>>  #include <asm/arch/system_manager.h>
>>>>>>>>>>>
>>>>>>>>>>> +#include "mmc_private.h"
>>>>>>>>>>>
>>>>>>>>>>>  static const struct socfpga_clock_manager *clock_manager_base =
>>>>>>>>>>>
>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
>>>>>>>>>>>
>>>>>>>>>>>  static const struct socfpga_system_manager *system_manager_base =
>>>>>>>>>>>
>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
>>>>>>>>>>>
>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
>>>>>>>>>>> +#define CAL_ROWS     7
>>>>>>>>>>> +#define CAL_COLS     8
>>>>>>>>>>> +
>>>>>>>>>>> +/*
>>>>>>>>>>> + * This function determines the largest rectangle filled with 1's
>>>>>>>>>>> and returns + * the middle. This functon can be optimized, for
>>>>>>>>>>> example using the algorithm + * from
>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
>>>>>>>>>>> 0529 + * It currently takes less than 1ms, while creating the input
>>>>>>>>>>> data takes ~5ms + * so there is not a real need to optimize it. +
>>>>>>>>>>> */
>>>>>>>>>>> +int find_calibration_point(unsigned char
>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
>>>>>>>>>>> cal_row, unsigned int * cal_col)
>>>>>>>>>>>
>>>>>>>>>>>  {
>>>>>>>>>>>
>>>>>>>>>>> -     unsigned int drvsel;
>>>>>>>>>>> -     unsigned int smplsel;
>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
>>>>>>>>>>> +     typedef struct
>>>>>>>>>>> +     {
>>>>>>>>>>> +             unsigned char height;
>>>>>>>>>>> +             unsigned char width;
>>>>>>>>>>> +             unsigned short area;
>>>>>>>>>>> +     } rect_cand_t;
>>>>>>>>>>> +
>>>>>>>>>>> +     /* Array with the rectangle candidates */
>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
>>>>>>>>>>> +     unsigned char height, width, k;
>>>>>>>>>>> +
>>>>>>>>>>> +     /* No solution if all combinations fail */
>>>>>>>>>>> +     if(sum == 0)
>>>>>>>>>>> +             return 1;
>>>>>>>>>>> +
>>>>>>>>>>> +     /* Simple solution if all combinations pass */
>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
>>>>>>>>>>> +             return 0;
>>>>>>>>>>> +     }
>>>>>>>>>>> +
>>>>>>>>>>> +     /*
>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in descending
>>>>>> area
>>>>>>>>>>> +      * order
>>>>>>>>>>> +      */
>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ; width--){
>>>>>>>>>>> +                     /* Add a new rectangle candidate */
>>>>>>>>>>> +                     rect_cands[cr_rect_cand].height = height;
>>>>>>>>>>> +                     rect_cands[cr_rect_cand].width = width;
>>>>>>>>>>> +                     rect_cands[cr_rect_cand].area = height * width;
>>>>>>>>>>> +                     cr_rect_cand++;
>>>>>>>>>>> +
>>>>>>>>>>> +                     /* First candidate it always in the right
>>>>>> position */
>>>>>>>>>>> +                     if(cr_rect_cand == 1)
>>>>>>>>>>> +                             continue;
>>>>>>>>>>> +
>>>>>>>>>>> +                     /*
>>>>>>>>>>> +                      * Put the candidate in right location to
>>>>>> maintain
>>>>>>>>>>> +                      * descending order
>>>>>>>>>>> +                      */
>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1; k--){
>>>>>>>>>>> +                             if(rect_cands[k-1].area <
>>>>>> rect_cands[k].area){
>>>>>>>>>>> +                                     rect_cand_t tmp =
>>>>>> rect_cands[k-1];
>>>>>>>>>>> +                                     rect_cands[k-1] = rect_cands[k];
>>>>>>>>>>> +                                     rect_cands[k] = tmp;
>>>>>>>>>>> +                             } else
>>>>>>>>>>> +                                     break;
>>>>>>>>>>> +                     }
>>>>>>>>>>> +             }
>>>>>>>>>>> +     }
>>>>>>>>>>> +
>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in descending area order
>>>>>>>>>>> */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
>>>>>>>>>>> +             unsigned char start_row, start_col;
>>>>>>>>>>> +             unsigned rect_width = rect_cands[k].width;
>>>>>>>>>>> +             unsigned rect_height = rect_cands[k].height;
>>>>>>>>>>> +
>>>>>>>>>>> +             /* Find the row and column where the candidate fits */
>>>>>>>>>>> +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
>>>>>> 1);
>>>>>>>>>>> +                  start_col++) {
>>>>>>>>>>> +                     for (start_row = 0; start_row < (CAL_ROWS -
>>>>>>>>>>> +                          rect_height + 1); start_row++) {
>>>>>>>>>>> +                             unsigned ok = 1;
>>>>>>>>>>> +                             unsigned add_col, add_row;
>>>>>>>>>>> +
>>>>>>>>>>> +                             /* Determine if the rectangle fits here
>>>>>> */
>>>>>>>>>>> +                             for (add_col = 0; (add_col < rect_width)
>>>>>> && ok;
>>>>>>>>>>> +                                  add_col++) {
>>>>>>>>>>> +                                     for (add_row = 0; add_row <
>>>>>> rect_height;
>>>>>>>>>>> +                                          add_row++) {
>>>>>>>>>>> +                                             if (!cal_results
>>>>>>>>>>> +                                                [start_row+add_row]
>>>>>> [start_col
>>>>>>>>>>> +                                                + add_col]) {
>>>>>>>>>>> +                                                     ok = 0;
>>>>>>>>>>> +                                                     break;
>>>>>>>>>>> +                                             }
>>>>>>>>>>> +                                     }
>>>>>>>>>>> +                             }
>>>>>>>>>>> +
>>>>>>>>>>> +                             /*
>>>>>>>>>>> +                              * Return 'middle' of rectangle in case
>>>>>> of
>>>>>>>>>>> +                              * success
>>>>>>>>>>> +                              */
>>>>>>>>>>> +                             if (ok) {
>>>>>>>>>>> +                                     if(rect_width > 1)
>>>>>>>>>>> +                                             rect_width--;
>>>>>>>>>>> +
>>>>>>>>>>> +                                     if(rect_height > 1)
>>>>>>>>>>> +                                             rect_height--;
>>>>>>>>>>> +
>>>>>>>>>>> +                                     *cal_row = start_row +
>>>>>>>>>>> +                                                (rect_height / 2);
>>>>>>>>>>> +                                     *cal_col = start_col +
>>>>>> (rect_width / 2);
>>>>>>>>>>> +
>>>>>>>>>>> +                                     return 0;
>>>>>>>>>>> +                             }
>>>>>>>>>>> +                     }
>>>>>>>>>>> +             }
>>>>>>>>>>> +     }
>>>>>>>>>>> +
>>>>>>>>>>> +     /* We could not fit any rectangle - return failure */
>>>>>>>>>>> +     return 1;
>>>>>>>>>>
>>>>>>>>>> Oh btw. please make sure to use errno.h and standard return codes ;
>>>>>>>>>> -EINVAL in this case I believe.
>>>>>>>>>
>>>>>>>>> Good suggestion, will fix in v2.
>>>>>>>>> Thanks
>>>>>>>>
>>>>>>>> Thanks. I was curious, is this really socfpga specific or can this
>>>>>>>> calibration be used on dwmmc in general -- thus on exynos and rockchip
>>>>>>>> systems -- as well? If it's generic to dwmmc, this should be moved into
>>>>>>>> the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
>>>>>>>> DWMMC recently.
>>>>>
>>>>> I didn't see you explicitly add Simon to the thread. Doing it here..
>>>>
>>>> One option is to put the function in the common dw_mmc.c file but have
>>>> it be called explicitly by drivers that want it (e.g. for now, just
>>>> socfpga). The code you have written does look generic and perhaps
>>>> should be used on other platforms,
>>>>
>>>>>
>>>>>>>
>>>>>>> I am not sure. But definitely we can make the calibration common enough
>>>>>>> if they required the calibration too. Let wait feedback from Simon.
>>>>>>
>>>>>
>>>>> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
>>>>> are using the drvsel and smpsel parameters. But I also think these
>>>>> parameters can
>>>>> be different for different types of SD card. Are you sure this
>>>>> function will cover those
>>>>> cases?
>>>>
>>>> Not at all, but perhaps that is something we will find out in the future.
>>>>
>>>
>>> Thanks Simon.
>>>
>>> I further checked today and noticed Exynos is setting up the clksel
>>> (sample clock and drive clock). But from exynos_dw_mmc.c, the value is
>>> coming from device tree. So I am notifying Jaehoon wonder the
>>> calibration might applicable for him. 

I think this patch should not be common code at all.
Of course, it seems that find_calibration_point function can be used at exynos.
But it's too complex and not readable.

And smpclk and drvsel are also not common. 
Depending on SoC, finding approach should be differed.
I don't know how smpclk and drvsel controlled, since i don't read TRM of other SoC.

Does it need to find the best clksmpl and drvsel value in bootloader?

Best Regards,
Jaehoon Chung

>>
>> Thanks for notifying this. But I can't find this patch at patchwork.
>> I'm not reading fully mail thread, so after reading mails, i will resend at mailing list.
> 
> Sure, here is the link :)
> http://lists.denx.de/pipermail/u-boot/2015-August/224566.html
> 
> Thanks
> Chin Liang
> 
> 
>>
>> Best Regards,
>> Jaehoon Chung
>>
>>>
>>> Jaehoon, this patch will do a calibration to determine the clksel value.
>>> Wonder is this something would help or applicable for Exynos? We are
>>> probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.
>>>
>>> Thanks
>>> Chin Liang
>>>
>>>> Regards,
>>>> Simon
>>>
>>>
>>>
>>
> 
> 
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-26  5:29                     ` Jaehoon Chung
@ 2015-08-26  5:47                       ` Chin Liang See
  2015-08-26  6:14                         ` Jaehoon Chung
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-08-26  5:47 UTC (permalink / raw)
  To: u-boot

On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
> Hi,
> 
> On 08/25/2015 12:08 PM, Chin Liang See wrote:
> > On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> >> Hi,
> >>
> >> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> >>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> >>>> Hi,
> >>>>
> >>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
> >>>>> +CC: Simon Glass
> >>>>>
> >>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> >>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> >>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> >>>>>>>>> Hi,
> >>>>>>>>
> >>>>>>>> Hi again,
> >>>>>>>>
> >>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> >>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> >>>>>>>>>>> Enable SDMMC calibration to determine the best setting for
> >>>>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
> >>>>>>>>>>> a change of card frequency and bus width. This is to ensure
> >>>>>>>>>>> reliable transmission between the controller and the card.
> >>>>>>>>>>>
> >>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> >>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> >>>>>
> >>>>> I think there's something wrong with your git scripts, I did not get this email.
> >>>>>
> >>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> >>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> >>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> >>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> >>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> >>>>>>>>>>> ---
> >>>>>>>>>>>
> >>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> >>>>>>>>>>>
> >>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> >>>>>>>>>>> insertions(+), 7 deletions(-)
> >>>>>>>>>>>
> >>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> >>>>>>>>>>> --- a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>> @@ -11,25 +11,140 @@
> >>>>>>>>>>>
> >>>>>>>>>>>  #include <asm/arch/dwmmc.h>
> >>>>>>>>>>>  #include <asm/arch/clock_manager.h>
> >>>>>>>>>>>  #include <asm/arch/system_manager.h>
> >>>>>>>>>>>
> >>>>>>>>>>> +#include "mmc_private.h"
> >>>>>>>>>>>
> >>>>>>>>>>>  static const struct socfpga_clock_manager *clock_manager_base =
> >>>>>>>>>>>
> >>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> >>>>>>>>>>>
> >>>>>>>>>>>  static const struct socfpga_system_manager *system_manager_base =
> >>>>>>>>>>>
> >>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> >>>>>>>>>>>
> >>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> >>>>>>>>>>> +#define CAL_ROWS     7
> >>>>>>>>>>> +#define CAL_COLS     8
> >>>>>>>>>>> +
> >>>>>>>>>>> +/*
> >>>>>>>>>>> + * This function determines the largest rectangle filled with 1's
> >>>>>>>>>>> and returns + * the middle. This functon can be optimized, for
> >>>>>>>>>>> example using the algorithm + * from
> >>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
> >>>>>>>>>>> 0529 + * It currently takes less than 1ms, while creating the input
> >>>>>>>>>>> data takes ~5ms + * so there is not a real need to optimize it. +
> >>>>>>>>>>> */
> >>>>>>>>>>> +int find_calibration_point(unsigned char
> >>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> >>>>>>>>>>> cal_row, unsigned int * cal_col)
> >>>>>>>>>>>
> >>>>>>>>>>>  {
> >>>>>>>>>>>
> >>>>>>>>>>> -     unsigned int drvsel;
> >>>>>>>>>>> -     unsigned int smplsel;
> >>>>>>>>>>> +     /* Structure containing a rectangle candidate */
> >>>>>>>>>>> +     typedef struct
> >>>>>>>>>>> +     {
> >>>>>>>>>>> +             unsigned char height;
> >>>>>>>>>>> +             unsigned char width;
> >>>>>>>>>>> +             unsigned short area;
> >>>>>>>>>>> +     } rect_cand_t;
> >>>>>>>>>>> +
> >>>>>>>>>>> +     /* Array with the rectangle candidates */
> >>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> >>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
> >>>>>>>>>>> +     unsigned char height, width, k;
> >>>>>>>>>>> +
> >>>>>>>>>>> +     /* No solution if all combinations fail */
> >>>>>>>>>>> +     if(sum == 0)
> >>>>>>>>>>> +             return 1;
> >>>>>>>>>>> +
> >>>>>>>>>>> +     /* Simple solution if all combinations pass */
> >>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> >>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> >>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> >>>>>>>>>>> +             return 0;
> >>>>>>>>>>> +     }
> >>>>>>>>>>> +
> >>>>>>>>>>> +     /*
> >>>>>>>>>>> +      * Create list of all possible sub-rectangles, in descending
> >>>>>> area
> >>>>>>>>>>> +      * order
> >>>>>>>>>>> +      */
> >>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> >>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ; width--){
> >>>>>>>>>>> +                     /* Add a new rectangle candidate */
> >>>>>>>>>>> +                     rect_cands[cr_rect_cand].height = height;
> >>>>>>>>>>> +                     rect_cands[cr_rect_cand].width = width;
> >>>>>>>>>>> +                     rect_cands[cr_rect_cand].area = height * width;
> >>>>>>>>>>> +                     cr_rect_cand++;
> >>>>>>>>>>> +
> >>>>>>>>>>> +                     /* First candidate it always in the right
> >>>>>> position */
> >>>>>>>>>>> +                     if(cr_rect_cand == 1)
> >>>>>>>>>>> +                             continue;
> >>>>>>>>>>> +
> >>>>>>>>>>> +                     /*
> >>>>>>>>>>> +                      * Put the candidate in right location to
> >>>>>> maintain
> >>>>>>>>>>> +                      * descending order
> >>>>>>>>>>> +                      */
> >>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1; k--){
> >>>>>>>>>>> +                             if(rect_cands[k-1].area <
> >>>>>> rect_cands[k].area){
> >>>>>>>>>>> +                                     rect_cand_t tmp =
> >>>>>> rect_cands[k-1];
> >>>>>>>>>>> +                                     rect_cands[k-1] = rect_cands[k];
> >>>>>>>>>>> +                                     rect_cands[k] = tmp;
> >>>>>>>>>>> +                             } else
> >>>>>>>>>>> +                                     break;
> >>>>>>>>>>> +                     }
> >>>>>>>>>>> +             }
> >>>>>>>>>>> +     }
> >>>>>>>>>>> +
> >>>>>>>>>>> +     /* Try to fit the rectangle candidates, in descending area order
> >>>>>>>>>>> */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> >>>>>>>>>>> +             unsigned char start_row, start_col;
> >>>>>>>>>>> +             unsigned rect_width = rect_cands[k].width;
> >>>>>>>>>>> +             unsigned rect_height = rect_cands[k].height;
> >>>>>>>>>>> +
> >>>>>>>>>>> +             /* Find the row and column where the candidate fits */
> >>>>>>>>>>> +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
> >>>>>> 1);
> >>>>>>>>>>> +                  start_col++) {
> >>>>>>>>>>> +                     for (start_row = 0; start_row < (CAL_ROWS -
> >>>>>>>>>>> +                          rect_height + 1); start_row++) {
> >>>>>>>>>>> +                             unsigned ok = 1;
> >>>>>>>>>>> +                             unsigned add_col, add_row;
> >>>>>>>>>>> +
> >>>>>>>>>>> +                             /* Determine if the rectangle fits here
> >>>>>> */
> >>>>>>>>>>> +                             for (add_col = 0; (add_col < rect_width)
> >>>>>> && ok;
> >>>>>>>>>>> +                                  add_col++) {
> >>>>>>>>>>> +                                     for (add_row = 0; add_row <
> >>>>>> rect_height;
> >>>>>>>>>>> +                                          add_row++) {
> >>>>>>>>>>> +                                             if (!cal_results
> >>>>>>>>>>> +                                                [start_row+add_row]
> >>>>>> [start_col
> >>>>>>>>>>> +                                                + add_col]) {
> >>>>>>>>>>> +                                                     ok = 0;
> >>>>>>>>>>> +                                                     break;
> >>>>>>>>>>> +                                             }
> >>>>>>>>>>> +                                     }
> >>>>>>>>>>> +                             }
> >>>>>>>>>>> +
> >>>>>>>>>>> +                             /*
> >>>>>>>>>>> +                              * Return 'middle' of rectangle in case
> >>>>>> of
> >>>>>>>>>>> +                              * success
> >>>>>>>>>>> +                              */
> >>>>>>>>>>> +                             if (ok) {
> >>>>>>>>>>> +                                     if(rect_width > 1)
> >>>>>>>>>>> +                                             rect_width--;
> >>>>>>>>>>> +
> >>>>>>>>>>> +                                     if(rect_height > 1)
> >>>>>>>>>>> +                                             rect_height--;
> >>>>>>>>>>> +
> >>>>>>>>>>> +                                     *cal_row = start_row +
> >>>>>>>>>>> +                                                (rect_height / 2);
> >>>>>>>>>>> +                                     *cal_col = start_col +
> >>>>>> (rect_width / 2);
> >>>>>>>>>>> +
> >>>>>>>>>>> +                                     return 0;
> >>>>>>>>>>> +                             }
> >>>>>>>>>>> +                     }
> >>>>>>>>>>> +             }
> >>>>>>>>>>> +     }
> >>>>>>>>>>> +
> >>>>>>>>>>> +     /* We could not fit any rectangle - return failure */
> >>>>>>>>>>> +     return 1;
> >>>>>>>>>>
> >>>>>>>>>> Oh btw. please make sure to use errno.h and standard return codes ;
> >>>>>>>>>> -EINVAL in this case I believe.
> >>>>>>>>>
> >>>>>>>>> Good suggestion, will fix in v2.
> >>>>>>>>> Thanks
> >>>>>>>>
> >>>>>>>> Thanks. I was curious, is this really socfpga specific or can this
> >>>>>>>> calibration be used on dwmmc in general -- thus on exynos and rockchip
> >>>>>>>> systems -- as well? If it's generic to dwmmc, this should be moved into
> >>>>>>>> the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
> >>>>>>>> DWMMC recently.
> >>>>>
> >>>>> I didn't see you explicitly add Simon to the thread. Doing it here..
> >>>>
> >>>> One option is to put the function in the common dw_mmc.c file but have
> >>>> it be called explicitly by drivers that want it (e.g. for now, just
> >>>> socfpga). The code you have written does look generic and perhaps
> >>>> should be used on other platforms,
> >>>>
> >>>>>
> >>>>>>>
> >>>>>>> I am not sure. But definitely we can make the calibration common enough
> >>>>>>> if they required the calibration too. Let wait feedback from Simon.
> >>>>>>
> >>>>>
> >>>>> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
> >>>>> are using the drvsel and smpsel parameters. But I also think these
> >>>>> parameters can
> >>>>> be different for different types of SD card. Are you sure this
> >>>>> function will cover those
> >>>>> cases?
> >>>>
> >>>> Not at all, but perhaps that is something we will find out in the future.
> >>>>
> >>>
> >>> Thanks Simon.
> >>>
> >>> I further checked today and noticed Exynos is setting up the clksel
> >>> (sample clock and drive clock). But from exynos_dw_mmc.c, the value is
> >>> coming from device tree. So I am notifying Jaehoon wonder the
> >>> calibration might applicable for him. 
> 
> I think this patch should not be common code at all.
> Of course, it seems that find_calibration_point function can be used at exynos.
> But it's too complex and not readable.
> 
> And smpclk and drvsel are also not common. 
> Depending on SoC, finding approach should be differed.
> I don't know how smpclk and drvsel controlled, since i don't read TRM of other SoC.
> 
> Does it need to find the best clksmpl and drvsel value in bootloader?
> 

Yah, its little complex as we try to find the best value for 2
parameters together. Its also due to the nature that we rely on full
complete transaction cycle to determine pass or fail (drvsel for out
while clksmp for in).

While finding the value, one of our customer have this issue. The SDMMC
communication doesn't work when they route the SDMMC slot few inches
away from the chip and running at high frequency.

With that, I shall introduce the code into socfpga_dw_mmc instead common
dw_mmc then. Wonder you would agree with that?

Thanks
Chin Liang


> Best Regards,
> Jaehoon Chung
> 
> >>
> >> Thanks for notifying this. But I can't find this patch at patchwork.
> >> I'm not reading fully mail thread, so after reading mails, i will resend at mailing list.
> > 
> > Sure, here is the link :)
> > http://lists.denx.de/pipermail/u-boot/2015-August/224566.html
> > 
> > Thanks
> > Chin Liang
> > 
> > 
> >>
> >> Best Regards,
> >> Jaehoon Chung
> >>
> >>>
> >>> Jaehoon, this patch will do a calibration to determine the clksel value.
> >>> Wonder is this something would help or applicable for Exynos? We are
> >>> probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.
> >>>
> >>> Thanks
> >>> Chin Liang
> >>>
> >>>> Regards,
> >>>> Simon
> >>>
> >>>
> >>>
> >>
> > 
> > 
> > _______________________________________________
> > U-Boot mailing list
> > U-Boot at lists.denx.de
> > http://lists.denx.de/mailman/listinfo/u-boot
> > 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-26  5:47                       ` Chin Liang See
@ 2015-08-26  6:14                         ` Jaehoon Chung
  2015-08-26  6:54                           ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Jaehoon Chung @ 2015-08-26  6:14 UTC (permalink / raw)
  To: u-boot

On 08/26/2015 02:47 PM, Chin Liang See wrote:
> On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
>> Hi,
>>
>> On 08/25/2015 12:08 PM, Chin Liang See wrote:
>>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
>>>> Hi,
>>>>
>>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
>>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
>>>>>>> +CC: Simon Glass
>>>>>>>
>>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
>>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
>>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Hi again,
>>>>>>>>>>
>>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
>>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting for
>>>>>>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
>>>>>>>>>>>>> a change of card frequency and bus width. This is to ensure
>>>>>>>>>>>>> reliable transmission between the controller and the card.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
>>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
>>>>>>>
>>>>>>> I think there's something wrong with your git scripts, I did not get this email.
>>>>>>>
>>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
>>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
>>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
>>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
>>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
>>>>>>>>>>>>> ---
>>>>>>>>>>>>>
>>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
>>>>>>>>>>>>>
>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
>>>>>>>>>>>>> insertions(+), 7 deletions(-)
>>>>>>>>>>>>>
>>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
>>>>>>>>>>>>> --- a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>> @@ -11,25 +11,140 @@
>>>>>>>>>>>>>
>>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
>>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
>>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
>>>>>>>>>>>>>
>>>>>>>>>>>>> +#include "mmc_private.h"
>>>>>>>>>>>>>
>>>>>>>>>>>>>  static const struct socfpga_clock_manager *clock_manager_base =
>>>>>>>>>>>>>
>>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
>>>>>>>>>>>>>
>>>>>>>>>>>>>  static const struct socfpga_system_manager *system_manager_base =
>>>>>>>>>>>>>
>>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
>>>>>>>>>>>>>
>>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
>>>>>>>>>>>>> +#define CAL_ROWS     7
>>>>>>>>>>>>> +#define CAL_COLS     8
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +/*
>>>>>>>>>>>>> + * This function determines the largest rectangle filled with 1's
>>>>>>>>>>>>> and returns + * the middle. This functon can be optimized, for
>>>>>>>>>>>>> example using the algorithm + * from
>>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
>>>>>>>>>>>>> 0529 + * It currently takes less than 1ms, while creating the input
>>>>>>>>>>>>> data takes ~5ms + * so there is not a real need to optimize it. +
>>>>>>>>>>>>> */
>>>>>>>>>>>>> +int find_calibration_point(unsigned char
>>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
>>>>>>>>>>>>> cal_row, unsigned int * cal_col)
>>>>>>>>>>>>>
>>>>>>>>>>>>>  {
>>>>>>>>>>>>>
>>>>>>>>>>>>> -     unsigned int drvsel;
>>>>>>>>>>>>> -     unsigned int smplsel;
>>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
>>>>>>>>>>>>> +     typedef struct
>>>>>>>>>>>>> +     {
>>>>>>>>>>>>> +             unsigned char height;
>>>>>>>>>>>>> +             unsigned char width;
>>>>>>>>>>>>> +             unsigned short area;
>>>>>>>>>>>>> +     } rect_cand_t;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +     /* Array with the rectangle candidates */
>>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
>>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
>>>>>>>>>>>>> +     unsigned char height, width, k;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +     /* No solution if all combinations fail */
>>>>>>>>>>>>> +     if(sum == 0)
>>>>>>>>>>>>> +             return 1;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
>>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
>>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
>>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
>>>>>>>>>>>>> +             return 0;
>>>>>>>>>>>>> +     }
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +     /*
>>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in descending
>>>>>>>> area
>>>>>>>>>>>>> +      * order
>>>>>>>>>>>>> +      */
>>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
>>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ; width--){
>>>>>>>>>>>>> +                     /* Add a new rectangle candidate */
>>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].height = height;
>>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].width = width;
>>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].area = height * width;
>>>>>>>>>>>>> +                     cr_rect_cand++;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +                     /* First candidate it always in the right
>>>>>>>> position */
>>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
>>>>>>>>>>>>> +                             continue;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +                     /*
>>>>>>>>>>>>> +                      * Put the candidate in right location to
>>>>>>>> maintain
>>>>>>>>>>>>> +                      * descending order
>>>>>>>>>>>>> +                      */
>>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1; k--){
>>>>>>>>>>>>> +                             if(rect_cands[k-1].area <
>>>>>>>> rect_cands[k].area){
>>>>>>>>>>>>> +                                     rect_cand_t tmp =
>>>>>>>> rect_cands[k-1];
>>>>>>>>>>>>> +                                     rect_cands[k-1] = rect_cands[k];
>>>>>>>>>>>>> +                                     rect_cands[k] = tmp;
>>>>>>>>>>>>> +                             } else
>>>>>>>>>>>>> +                                     break;
>>>>>>>>>>>>> +                     }
>>>>>>>>>>>>> +             }
>>>>>>>>>>>>> +     }
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in descending area order
>>>>>>>>>>>>> */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
>>>>>>>>>>>>> +             unsigned char start_row, start_col;
>>>>>>>>>>>>> +             unsigned rect_width = rect_cands[k].width;
>>>>>>>>>>>>> +             unsigned rect_height = rect_cands[k].height;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +             /* Find the row and column where the candidate fits */
>>>>>>>>>>>>> +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
>>>>>>>> 1);
>>>>>>>>>>>>> +                  start_col++) {
>>>>>>>>>>>>> +                     for (start_row = 0; start_row < (CAL_ROWS -
>>>>>>>>>>>>> +                          rect_height + 1); start_row++) {
>>>>>>>>>>>>> +                             unsigned ok = 1;
>>>>>>>>>>>>> +                             unsigned add_col, add_row;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +                             /* Determine if the rectangle fits here
>>>>>>>> */
>>>>>>>>>>>>> +                             for (add_col = 0; (add_col < rect_width)
>>>>>>>> && ok;
>>>>>>>>>>>>> +                                  add_col++) {
>>>>>>>>>>>>> +                                     for (add_row = 0; add_row <
>>>>>>>> rect_height;
>>>>>>>>>>>>> +                                          add_row++) {
>>>>>>>>>>>>> +                                             if (!cal_results
>>>>>>>>>>>>> +                                                [start_row+add_row]
>>>>>>>> [start_col
>>>>>>>>>>>>> +                                                + add_col]) {
>>>>>>>>>>>>> +                                                     ok = 0;
>>>>>>>>>>>>> +                                                     break;
>>>>>>>>>>>>> +                                             }
>>>>>>>>>>>>> +                                     }
>>>>>>>>>>>>> +                             }
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +                             /*
>>>>>>>>>>>>> +                              * Return 'middle' of rectangle in case
>>>>>>>> of
>>>>>>>>>>>>> +                              * success
>>>>>>>>>>>>> +                              */
>>>>>>>>>>>>> +                             if (ok) {
>>>>>>>>>>>>> +                                     if(rect_width > 1)
>>>>>>>>>>>>> +                                             rect_width--;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +                                     if(rect_height > 1)
>>>>>>>>>>>>> +                                             rect_height--;
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +                                     *cal_row = start_row +
>>>>>>>>>>>>> +                                                (rect_height / 2);
>>>>>>>>>>>>> +                                     *cal_col = start_col +
>>>>>>>> (rect_width / 2);
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +                                     return 0;
>>>>>>>>>>>>> +                             }
>>>>>>>>>>>>> +                     }
>>>>>>>>>>>>> +             }
>>>>>>>>>>>>> +     }
>>>>>>>>>>>>> +
>>>>>>>>>>>>> +     /* We could not fit any rectangle - return failure */
>>>>>>>>>>>>> +     return 1;
>>>>>>>>>>>>
>>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard return codes ;
>>>>>>>>>>>> -EINVAL in this case I believe.
>>>>>>>>>>>
>>>>>>>>>>> Good suggestion, will fix in v2.
>>>>>>>>>>> Thanks
>>>>>>>>>>
>>>>>>>>>> Thanks. I was curious, is this really socfpga specific or can this
>>>>>>>>>> calibration be used on dwmmc in general -- thus on exynos and rockchip
>>>>>>>>>> systems -- as well? If it's generic to dwmmc, this should be moved into
>>>>>>>>>> the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
>>>>>>>>>> DWMMC recently.
>>>>>>>
>>>>>>> I didn't see you explicitly add Simon to the thread. Doing it here..
>>>>>>
>>>>>> One option is to put the function in the common dw_mmc.c file but have
>>>>>> it be called explicitly by drivers that want it (e.g. for now, just
>>>>>> socfpga). The code you have written does look generic and perhaps
>>>>>> should be used on other platforms,
>>>>>>
>>>>>>>
>>>>>>>>>
>>>>>>>>> I am not sure. But definitely we can make the calibration common enough
>>>>>>>>> if they required the calibration too. Let wait feedback from Simon.
>>>>>>>>
>>>>>>>
>>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
>>>>>>> are using the drvsel and smpsel parameters. But I also think these
>>>>>>> parameters can
>>>>>>> be different for different types of SD card. Are you sure this
>>>>>>> function will cover those
>>>>>>> cases?
>>>>>>
>>>>>> Not at all, but perhaps that is something we will find out in the future.
>>>>>>
>>>>>
>>>>> Thanks Simon.
>>>>>
>>>>> I further checked today and noticed Exynos is setting up the clksel
>>>>> (sample clock and drive clock). But from exynos_dw_mmc.c, the value is
>>>>> coming from device tree. So I am notifying Jaehoon wonder the
>>>>> calibration might applicable for him. 
>>
>> I think this patch should not be common code at all.
>> Of course, it seems that find_calibration_point function can be used at exynos.
>> But it's too complex and not readable.
>>
>> And smpclk and drvsel are also not common. 
>> Depending on SoC, finding approach should be differed.
>> I don't know how smpclk and drvsel controlled, since i don't read TRM of other SoC.
>>
>> Does it need to find the best clksmpl and drvsel value in bootloader?
>>
> 
> Yah, its little complex as we try to find the best value for 2
> parameters together. Its also due to the nature that we rely on full
> complete transaction cycle to determine pass or fail (drvsel for out
> while clksmp for in).

In my experiment, spmlclk value is more important than drvsel.
Anyway, CAL_ROWS and CAL_COLS are candiates, right?
If it can be passed by parameter from each SoC dwmmc controller, that function should be located into dwmmc.c.
Because drvsel and smplclk bits should be difference at each SoC specific register or Generic dwmmc(UHS_REG_EXT regster).

Do you have the plan that change the more generic code than now?

> 
> While finding the value, one of our customer have this issue. The SDMMC
> communication doesn't work when they route the SDMMC slot few inches
> away from the chip and running at high frequency.

High frequency? DDR50 mode? I know that it's not implemented for the upper mode at bootloader.
Is it related with controlling power, not controlling cmu?

Best Regards,
Jaehoon Chung

> 
> With that, I shall introduce the code into socfpga_dw_mmc instead common
> dw_mmc then. Wonder you would agree with that?
> 
> Thanks
> Chin Liang
> 
> 
>> Best Regards,
>> Jaehoon Chung
>>
>>>>
>>>> Thanks for notifying this. But I can't find this patch at patchwork.
>>>> I'm not reading fully mail thread, so after reading mails, i will resend at mailing list.
>>>
>>> Sure, here is the link :)
>>> http://lists.denx.de/pipermail/u-boot/2015-August/224566.html
>>>
>>> Thanks
>>> Chin Liang
>>>
>>>
>>>>
>>>> Best Regards,
>>>> Jaehoon Chung
>>>>
>>>>>
>>>>> Jaehoon, this patch will do a calibration to determine the clksel value.
>>>>> Wonder is this something would help or applicable for Exynos? We are
>>>>> probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.
>>>>>
>>>>> Thanks
>>>>> Chin Liang
>>>>>
>>>>>> Regards,
>>>>>> Simon
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> U-Boot mailing list
>>> U-Boot at lists.denx.de
>>> http://lists.denx.de/mailman/listinfo/u-boot
>>>
>>
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-26  6:14                         ` Jaehoon Chung
@ 2015-08-26  6:54                           ` Chin Liang See
  2015-09-01  8:54                             ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-08-26  6:54 UTC (permalink / raw)
  To: u-boot

On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
> On 08/26/2015 02:47 PM, Chin Liang See wrote:
> > On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
> >> Hi,
> >>
> >> On 08/25/2015 12:08 PM, Chin Liang See wrote:
> >>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> >>>> Hi,
> >>>>
> >>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> >>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
> >>>>>>> +CC: Simon Glass
> >>>>>>>
> >>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> >>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> >>>>>>>>> Hi,
> >>>>>>>>>
> >>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> >>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> >>>>>>>>>>> Hi,
> >>>>>>>>>>
> >>>>>>>>>> Hi again,
> >>>>>>>>>>
> >>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> >>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> >>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting for
> >>>>>>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
> >>>>>>>>>>>>> a change of card frequency and bus width. This is to ensure
> >>>>>>>>>>>>> reliable transmission between the controller and the card.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> >>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> >>>>>>>
> >>>>>>> I think there's something wrong with your git scripts, I did not get this email.
> >>>>>>>
> >>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> >>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> >>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> >>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> >>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> >>>>>>>>>>>>> ---
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> >>>>>>>>>>>>> insertions(+), 7 deletions(-)
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> >>>>>>>>>>>>> --- a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>>>> @@ -11,25 +11,140 @@
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
> >>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
> >>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> +#include "mmc_private.h"
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>  static const struct socfpga_clock_manager *clock_manager_base =
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>  static const struct socfpga_system_manager *system_manager_base =
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> >>>>>>>>>>>>> +#define CAL_ROWS     7
> >>>>>>>>>>>>> +#define CAL_COLS     8
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +/*
> >>>>>>>>>>>>> + * This function determines the largest rectangle filled with 1's
> >>>>>>>>>>>>> and returns + * the middle. This functon can be optimized, for
> >>>>>>>>>>>>> example using the algorithm + * from
> >>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
> >>>>>>>>>>>>> 0529 + * It currently takes less than 1ms, while creating the input
> >>>>>>>>>>>>> data takes ~5ms + * so there is not a real need to optimize it. +
> >>>>>>>>>>>>> */
> >>>>>>>>>>>>> +int find_calibration_point(unsigned char
> >>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> >>>>>>>>>>>>> cal_row, unsigned int * cal_col)
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>  {
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> -     unsigned int drvsel;
> >>>>>>>>>>>>> -     unsigned int smplsel;
> >>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
> >>>>>>>>>>>>> +     typedef struct
> >>>>>>>>>>>>> +     {
> >>>>>>>>>>>>> +             unsigned char height;
> >>>>>>>>>>>>> +             unsigned char width;
> >>>>>>>>>>>>> +             unsigned short area;
> >>>>>>>>>>>>> +     } rect_cand_t;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +     /* Array with the rectangle candidates */
> >>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> >>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
> >>>>>>>>>>>>> +     unsigned char height, width, k;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +     /* No solution if all combinations fail */
> >>>>>>>>>>>>> +     if(sum == 0)
> >>>>>>>>>>>>> +             return 1;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
> >>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> >>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> >>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> >>>>>>>>>>>>> +             return 0;
> >>>>>>>>>>>>> +     }
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +     /*
> >>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in descending
> >>>>>>>> area
> >>>>>>>>>>>>> +      * order
> >>>>>>>>>>>>> +      */
> >>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> >>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ; width--){
> >>>>>>>>>>>>> +                     /* Add a new rectangle candidate */
> >>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].height = height;
> >>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].width = width;
> >>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].area = height * width;
> >>>>>>>>>>>>> +                     cr_rect_cand++;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +                     /* First candidate it always in the right
> >>>>>>>> position */
> >>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
> >>>>>>>>>>>>> +                             continue;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +                     /*
> >>>>>>>>>>>>> +                      * Put the candidate in right location to
> >>>>>>>> maintain
> >>>>>>>>>>>>> +                      * descending order
> >>>>>>>>>>>>> +                      */
> >>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1; k--){
> >>>>>>>>>>>>> +                             if(rect_cands[k-1].area <
> >>>>>>>> rect_cands[k].area){
> >>>>>>>>>>>>> +                                     rect_cand_t tmp =
> >>>>>>>> rect_cands[k-1];
> >>>>>>>>>>>>> +                                     rect_cands[k-1] = rect_cands[k];
> >>>>>>>>>>>>> +                                     rect_cands[k] = tmp;
> >>>>>>>>>>>>> +                             } else
> >>>>>>>>>>>>> +                                     break;
> >>>>>>>>>>>>> +                     }
> >>>>>>>>>>>>> +             }
> >>>>>>>>>>>>> +     }
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in descending area order
> >>>>>>>>>>>>> */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> >>>>>>>>>>>>> +             unsigned char start_row, start_col;
> >>>>>>>>>>>>> +             unsigned rect_width = rect_cands[k].width;
> >>>>>>>>>>>>> +             unsigned rect_height = rect_cands[k].height;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +             /* Find the row and column where the candidate fits */
> >>>>>>>>>>>>> +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
> >>>>>>>> 1);
> >>>>>>>>>>>>> +                  start_col++) {
> >>>>>>>>>>>>> +                     for (start_row = 0; start_row < (CAL_ROWS -
> >>>>>>>>>>>>> +                          rect_height + 1); start_row++) {
> >>>>>>>>>>>>> +                             unsigned ok = 1;
> >>>>>>>>>>>>> +                             unsigned add_col, add_row;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +                             /* Determine if the rectangle fits here
> >>>>>>>> */
> >>>>>>>>>>>>> +                             for (add_col = 0; (add_col < rect_width)
> >>>>>>>> && ok;
> >>>>>>>>>>>>> +                                  add_col++) {
> >>>>>>>>>>>>> +                                     for (add_row = 0; add_row <
> >>>>>>>> rect_height;
> >>>>>>>>>>>>> +                                          add_row++) {
> >>>>>>>>>>>>> +                                             if (!cal_results
> >>>>>>>>>>>>> +                                                [start_row+add_row]
> >>>>>>>> [start_col
> >>>>>>>>>>>>> +                                                + add_col]) {
> >>>>>>>>>>>>> +                                                     ok = 0;
> >>>>>>>>>>>>> +                                                     break;
> >>>>>>>>>>>>> +                                             }
> >>>>>>>>>>>>> +                                     }
> >>>>>>>>>>>>> +                             }
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +                             /*
> >>>>>>>>>>>>> +                              * Return 'middle' of rectangle in case
> >>>>>>>> of
> >>>>>>>>>>>>> +                              * success
> >>>>>>>>>>>>> +                              */
> >>>>>>>>>>>>> +                             if (ok) {
> >>>>>>>>>>>>> +                                     if(rect_width > 1)
> >>>>>>>>>>>>> +                                             rect_width--;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +                                     if(rect_height > 1)
> >>>>>>>>>>>>> +                                             rect_height--;
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +                                     *cal_row = start_row +
> >>>>>>>>>>>>> +                                                (rect_height / 2);
> >>>>>>>>>>>>> +                                     *cal_col = start_col +
> >>>>>>>> (rect_width / 2);
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +                                     return 0;
> >>>>>>>>>>>>> +                             }
> >>>>>>>>>>>>> +                     }
> >>>>>>>>>>>>> +             }
> >>>>>>>>>>>>> +     }
> >>>>>>>>>>>>> +
> >>>>>>>>>>>>> +     /* We could not fit any rectangle - return failure */
> >>>>>>>>>>>>> +     return 1;
> >>>>>>>>>>>>
> >>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard return codes ;
> >>>>>>>>>>>> -EINVAL in this case I believe.
> >>>>>>>>>>>
> >>>>>>>>>>> Good suggestion, will fix in v2.
> >>>>>>>>>>> Thanks
> >>>>>>>>>>
> >>>>>>>>>> Thanks. I was curious, is this really socfpga specific or can this
> >>>>>>>>>> calibration be used on dwmmc in general -- thus on exynos and rockchip
> >>>>>>>>>> systems -- as well? If it's generic to dwmmc, this should be moved into
> >>>>>>>>>> the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
> >>>>>>>>>> DWMMC recently.
> >>>>>>>
> >>>>>>> I didn't see you explicitly add Simon to the thread. Doing it here..
> >>>>>>
> >>>>>> One option is to put the function in the common dw_mmc.c file but have
> >>>>>> it be called explicitly by drivers that want it (e.g. for now, just
> >>>>>> socfpga). The code you have written does look generic and perhaps
> >>>>>> should be used on other platforms,
> >>>>>>
> >>>>>>>
> >>>>>>>>>
> >>>>>>>>> I am not sure. But definitely we can make the calibration common enough
> >>>>>>>>> if they required the calibration too. Let wait feedback from Simon.
> >>>>>>>>
> >>>>>>>
> >>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
> >>>>>>> are using the drvsel and smpsel parameters. But I also think these
> >>>>>>> parameters can
> >>>>>>> be different for different types of SD card. Are you sure this
> >>>>>>> function will cover those
> >>>>>>> cases?
> >>>>>>
> >>>>>> Not at all, but perhaps that is something we will find out in the future.
> >>>>>>
> >>>>>
> >>>>> Thanks Simon.
> >>>>>
> >>>>> I further checked today and noticed Exynos is setting up the clksel
> >>>>> (sample clock and drive clock). But from exynos_dw_mmc.c, the value is
> >>>>> coming from device tree. So I am notifying Jaehoon wonder the
> >>>>> calibration might applicable for him. 
> >>
> >> I think this patch should not be common code at all.
> >> Of course, it seems that find_calibration_point function can be used at exynos.
> >> But it's too complex and not readable.
> >>
> >> And smpclk and drvsel are also not common. 
> >> Depending on SoC, finding approach should be differed.
> >> I don't know how smpclk and drvsel controlled, since i don't read TRM of other SoC.
> >>
> >> Does it need to find the best clksmpl and drvsel value in bootloader?
> >>
> > 
> > Yah, its little complex as we try to find the best value for 2
> > parameters together. Its also due to the nature that we rely on full
> > complete transaction cycle to determine pass or fail (drvsel for out
> > while clksmp for in).
> 
> In my experiment, spmlclk value is more important than drvsel.
> Anyway, CAL_ROWS and CAL_COLS are candiates, right?

Yup, they are representing the value permutation for smplclk and drvsel.

> If it can be passed by parameter from each SoC dwmmc controller, that function should be located into dwmmc.c.
> Because drvsel and smplclk bits should be difference at each SoC specific register or Generic dwmmc(UHS_REG_EXT regster).
> 
> Do you have the plan that change the more generic code than now?

Actually I look back and different SoC have different register location
for drvsel and smplclk. They are not located within dwmmc controller
registers. As of now, they are configure within the callback function of
clksel, I believe that should good.

> 
> > 
> > While finding the value, one of our customer have this issue. The SDMMC
> > communication doesn't work when they route the SDMMC slot few inches
> > away from the chip and running at high frequency.
> 
> High frequency? DDR50 mode? I know that it's not implemented for the upper mode at bootloader.
> Is it related with controlling power, not controlling cmu?

Actually I am comparing the enumeration and normal run (SDR25). The
failure is spotted during data transfer such as fatload. Wonder what is
cmu? :)

Thanks
Chin Liang


> 
> Best Regards,
> Jaehoon Chung
> 
> > 
> > With that, I shall introduce the code into socfpga_dw_mmc instead common
> > dw_mmc then. Wonder you would agree with that?
> > 
> > Thanks
> > Chin Liang
> > 
> > 
> >> Best Regards,
> >> Jaehoon Chung
> >>
> >>>>
> >>>> Thanks for notifying this. But I can't find this patch at patchwork.
> >>>> I'm not reading fully mail thread, so after reading mails, i will resend at mailing list.
> >>>
> >>> Sure, here is the link :)
> >>> http://lists.denx.de/pipermail/u-boot/2015-August/224566.html
> >>>
> >>> Thanks
> >>> Chin Liang
> >>>
> >>>
> >>>>
> >>>> Best Regards,
> >>>> Jaehoon Chung
> >>>>
> >>>>>
> >>>>> Jaehoon, this patch will do a calibration to determine the clksel value.
> >>>>> Wonder is this something would help or applicable for Exynos? We are
> >>>>> probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.
> >>>>>
> >>>>> Thanks
> >>>>> Chin Liang
> >>>>>
> >>>>>> Regards,
> >>>>>> Simon
> >>>>>
> >>>>>
> >>>>>
> >>>>
> >>>
> >>>
> >>> _______________________________________________
> >>> U-Boot mailing list
> >>> U-Boot at lists.denx.de
> >>> http://lists.denx.de/mailman/listinfo/u-boot
> >>>
> >>
> > 
> > 
> > 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-08-26  6:54                           ` Chin Liang See
@ 2015-09-01  8:54                             ` Chin Liang See
  2015-09-01  9:01                               ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-09-01  8:54 UTC (permalink / raw)
  To: u-boot

On Wed, 2015-08-26 at 01:54 -0500, Chin Liang See wrote:
> On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
> > On 08/26/2015 02:47 PM, Chin Liang See wrote:
> > > On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
> > >> Hi,
> > >>
> > >> On 08/25/2015 12:08 PM, Chin Liang See wrote:
> > >>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> > >>>> Hi,
> > >>>>
> > >>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> > >>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> > >>>>>> Hi,
> > >>>>>>
> > >>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> wrote:
> > >>>>>>> +CC: Simon Glass
> > >>>>>>>
> > >>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> wrote:
> > >>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See wrote:
> > >>>>>>>>> Hi,
> > >>>>>>>>>
> > >>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> > >>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See wrote:
> > >>>>>>>>>>> Hi,
> > >>>>>>>>>>
> > >>>>>>>>>> Hi again,
> > >>>>>>>>>>
> > >>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> > >>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See wrote:
> > >>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting for
> > >>>>>>>>>>>>> drvsel and smpsel. It will be triggered whenever there is
> > >>>>>>>>>>>>> a change of card frequency and bus width. This is to ensure
> > >>>>>>>>>>>>> reliable transmission between the controller and the card.
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> > >>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > >>>>>>>
> > >>>>>>> I think there's something wrong with your git scripts, I did not get this email.
> > >>>>>>>
> > >>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> > >>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> > >>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> > >>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> > >>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> > >>>>>>>>>>>>> ---
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 180
> > >>>>>>>>>>>>> insertions(+), 7 deletions(-)
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > >>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c 100644
> > >>>>>>>>>>>>> --- a/drivers/mmc/socfpga_dw_mmc.c
> > >>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> > >>>>>>>>>>>>> @@ -11,25 +11,140 @@
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
> > >>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
> > >>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> +#include "mmc_private.h"
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>>  static const struct socfpga_clock_manager *clock_manager_base =
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>>  static const struct socfpga_system_manager *system_manager_base =
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host *host)
> > >>>>>>>>>>>>> +#define CAL_ROWS     7
> > >>>>>>>>>>>>> +#define CAL_COLS     8
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +/*
> > >>>>>>>>>>>>> + * This function determines the largest rectangle filled with 1's
> > >>>>>>>>>>>>> and returns + * the middle. This functon can be optimized, for
> > >>>>>>>>>>>>> example using the algorithm + * from
> > >>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-problem/18441
> > >>>>>>>>>>>>> 0529 + * It currently takes less than 1ms, while creating the input
> > >>>>>>>>>>>>> data takes ~5ms + * so there is not a real need to optimize it. +
> > >>>>>>>>>>>>> */
> > >>>>>>>>>>>>> +int find_calibration_point(unsigned char
> > >>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum, unsigned int *
> > >>>>>>>>>>>>> cal_row, unsigned int * cal_col)
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>>  {
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> -     unsigned int drvsel;
> > >>>>>>>>>>>>> -     unsigned int smplsel;
> > >>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
> > >>>>>>>>>>>>> +     typedef struct
> > >>>>>>>>>>>>> +     {
> > >>>>>>>>>>>>> +             unsigned char height;
> > >>>>>>>>>>>>> +             unsigned char width;
> > >>>>>>>>>>>>> +             unsigned short area;
> > >>>>>>>>>>>>> +     } rect_cand_t;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +     /* Array with the rectangle candidates */
> > >>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > >>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
> > >>>>>>>>>>>>> +     unsigned char height, width, k;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +     /* No solution if all combinations fail */
> > >>>>>>>>>>>>> +     if(sum == 0)
> > >>>>>>>>>>>>> +             return 1;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
> > >>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> > >>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> > >>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> > >>>>>>>>>>>>> +             return 0;
> > >>>>>>>>>>>>> +     }
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +     /*
> > >>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in descending
> > >>>>>>>> area
> > >>>>>>>>>>>>> +      * order
> > >>>>>>>>>>>>> +      */
> > >>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> > >>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ; width--){
> > >>>>>>>>>>>>> +                     /* Add a new rectangle candidate */
> > >>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].height = height;
> > >>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].width = width;
> > >>>>>>>>>>>>> +                     rect_cands[cr_rect_cand].area = height * width;
> > >>>>>>>>>>>>> +                     cr_rect_cand++;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +                     /* First candidate it always in the right
> > >>>>>>>> position */
> > >>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
> > >>>>>>>>>>>>> +                             continue;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +                     /*
> > >>>>>>>>>>>>> +                      * Put the candidate in right location to
> > >>>>>>>> maintain
> > >>>>>>>>>>>>> +                      * descending order
> > >>>>>>>>>>>>> +                      */
> > >>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1; k--){
> > >>>>>>>>>>>>> +                             if(rect_cands[k-1].area <
> > >>>>>>>> rect_cands[k].area){
> > >>>>>>>>>>>>> +                                     rect_cand_t tmp =
> > >>>>>>>> rect_cands[k-1];
> > >>>>>>>>>>>>> +                                     rect_cands[k-1] = rect_cands[k];
> > >>>>>>>>>>>>> +                                     rect_cands[k] = tmp;
> > >>>>>>>>>>>>> +                             } else
> > >>>>>>>>>>>>> +                                     break;
> > >>>>>>>>>>>>> +                     }
> > >>>>>>>>>>>>> +             }
> > >>>>>>>>>>>>> +     }
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in descending area order
> > >>>>>>>>>>>>> */ +  for(k = 0; k < CAL_ROWS * CAL_COLS; k++) {
> > >>>>>>>>>>>>> +             unsigned char start_row, start_col;
> > >>>>>>>>>>>>> +             unsigned rect_width = rect_cands[k].width;
> > >>>>>>>>>>>>> +             unsigned rect_height = rect_cands[k].height;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +             /* Find the row and column where the candidate fits */
> > >>>>>>>>>>>>> +             for (start_col = 0; start_col < (CAL_COLS - rect_width +
> > >>>>>>>> 1);
> > >>>>>>>>>>>>> +                  start_col++) {
> > >>>>>>>>>>>>> +                     for (start_row = 0; start_row < (CAL_ROWS -
> > >>>>>>>>>>>>> +                          rect_height + 1); start_row++) {
> > >>>>>>>>>>>>> +                             unsigned ok = 1;
> > >>>>>>>>>>>>> +                             unsigned add_col, add_row;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +                             /* Determine if the rectangle fits here
> > >>>>>>>> */
> > >>>>>>>>>>>>> +                             for (add_col = 0; (add_col < rect_width)
> > >>>>>>>> && ok;
> > >>>>>>>>>>>>> +                                  add_col++) {
> > >>>>>>>>>>>>> +                                     for (add_row = 0; add_row <
> > >>>>>>>> rect_height;
> > >>>>>>>>>>>>> +                                          add_row++) {
> > >>>>>>>>>>>>> +                                             if (!cal_results
> > >>>>>>>>>>>>> +                                                [start_row+add_row]
> > >>>>>>>> [start_col
> > >>>>>>>>>>>>> +                                                + add_col]) {
> > >>>>>>>>>>>>> +                                                     ok = 0;
> > >>>>>>>>>>>>> +                                                     break;
> > >>>>>>>>>>>>> +                                             }
> > >>>>>>>>>>>>> +                                     }
> > >>>>>>>>>>>>> +                             }
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +                             /*
> > >>>>>>>>>>>>> +                              * Return 'middle' of rectangle in case
> > >>>>>>>> of
> > >>>>>>>>>>>>> +                              * success
> > >>>>>>>>>>>>> +                              */
> > >>>>>>>>>>>>> +                             if (ok) {
> > >>>>>>>>>>>>> +                                     if(rect_width > 1)
> > >>>>>>>>>>>>> +                                             rect_width--;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +                                     if(rect_height > 1)
> > >>>>>>>>>>>>> +                                             rect_height--;
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +                                     *cal_row = start_row +
> > >>>>>>>>>>>>> +                                                (rect_height / 2);
> > >>>>>>>>>>>>> +                                     *cal_col = start_col +
> > >>>>>>>> (rect_width / 2);
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +                                     return 0;
> > >>>>>>>>>>>>> +                             }
> > >>>>>>>>>>>>> +                     }
> > >>>>>>>>>>>>> +             }
> > >>>>>>>>>>>>> +     }
> > >>>>>>>>>>>>> +
> > >>>>>>>>>>>>> +     /* We could not fit any rectangle - return failure */
> > >>>>>>>>>>>>> +     return 1;
> > >>>>>>>>>>>>
> > >>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard return codes ;
> > >>>>>>>>>>>> -EINVAL in this case I believe.
> > >>>>>>>>>>>
> > >>>>>>>>>>> Good suggestion, will fix in v2.
> > >>>>>>>>>>> Thanks
> > >>>>>>>>>>
> > >>>>>>>>>> Thanks. I was curious, is this really socfpga specific or can this
> > >>>>>>>>>> calibration be used on dwmmc in general -- thus on exynos and rockchip
> > >>>>>>>>>> systems -- as well? If it's generic to dwmmc, this should be moved into
> > >>>>>>>>>> the dwmmc core code. Also, I am CCing Simon, he's been plumbing in the
> > >>>>>>>>>> DWMMC recently.
> > >>>>>>>
> > >>>>>>> I didn't see you explicitly add Simon to the thread. Doing it here..
> > >>>>>>
> > >>>>>> One option is to put the function in the common dw_mmc.c file but have
> > >>>>>> it be called explicitly by drivers that want it (e.g. for now, just
> > >>>>>> socfpga). The code you have written does look generic and perhaps
> > >>>>>> should be used on other platforms,
> > >>>>>>
> > >>>>>>>
> > >>>>>>>>>
> > >>>>>>>>> I am not sure. But definitely we can make the calibration common enough
> > >>>>>>>>> if they required the calibration too. Let wait feedback from Simon.
> > >>>>>>>>
> > >>>>>>>
> > >>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA, Exynos and Rockchip
> > >>>>>>> are using the drvsel and smpsel parameters. But I also think these
> > >>>>>>> parameters can
> > >>>>>>> be different for different types of SD card. Are you sure this
> > >>>>>>> function will cover those
> > >>>>>>> cases?
> > >>>>>>
> > >>>>>> Not at all, but perhaps that is something we will find out in the future.
> > >>>>>>
> > >>>>>
> > >>>>> Thanks Simon.
> > >>>>>
> > >>>>> I further checked today and noticed Exynos is setting up the clksel
> > >>>>> (sample clock and drive clock). But from exynos_dw_mmc.c, the value is
> > >>>>> coming from device tree. So I am notifying Jaehoon wonder the
> > >>>>> calibration might applicable for him. 
> > >>
> > >> I think this patch should not be common code at all.
> > >> Of course, it seems that find_calibration_point function can be used at exynos.
> > >> But it's too complex and not readable.
> > >>
> > >> And smpclk and drvsel are also not common. 
> > >> Depending on SoC, finding approach should be differed.
> > >> I don't know how smpclk and drvsel controlled, since i don't read TRM of other SoC.
> > >>
> > >> Does it need to find the best clksmpl and drvsel value in bootloader?
> > >>
> > > 
> > > Yah, its little complex as we try to find the best value for 2
> > > parameters together. Its also due to the nature that we rely on full
> > > complete transaction cycle to determine pass or fail (drvsel for out
> > > while clksmp for in).
> > 
> > In my experiment, spmlclk value is more important than drvsel.
> > Anyway, CAL_ROWS and CAL_COLS are candiates, right?
> 
> Yup, they are representing the value permutation for smplclk and drvsel.
> 
> > If it can be passed by parameter from each SoC dwmmc controller, that function should be located into dwmmc.c.
> > Because drvsel and smplclk bits should be difference at each SoC specific register or Generic dwmmc(UHS_REG_EXT regster).
> > 
> > Do you have the plan that change the more generic code than now?
> 
> Actually I look back and different SoC have different register location
> for drvsel and smplclk. They are not located within dwmmc controller
> registers. As of now, they are configure within the callback function of
> clksel, I believe that should good.

For this case, I presume the change would applicable for socfpga only
instead common dw_mmc. If everyone agreed, I shall send in new revision
of the patch.

Thanks
Chin Liang

> 
> > 
> > > 
> > > While finding the value, one of our customer have this issue. The SDMMC
> > > communication doesn't work when they route the SDMMC slot few inches
> > > away from the chip and running at high frequency.
> > 
> > High frequency? DDR50 mode? I know that it's not implemented for the upper mode at bootloader.
> > Is it related with controlling power, not controlling cmu?
> 
> Actually I am comparing the enumeration and normal run (SDR25). The
> failure is spotted during data transfer such as fatload. Wonder what is
> cmu? :)
> 
> Thanks
> Chin Liang
> 
> 
> > 
> > Best Regards,
> > Jaehoon Chung
> > 
> > > 
> > > With that, I shall introduce the code into socfpga_dw_mmc instead common
> > > dw_mmc then. Wonder you would agree with that?
> > > 
> > > Thanks
> > > Chin Liang
> > > 
> > > 
> > >> Best Regards,
> > >> Jaehoon Chung
> > >>
> > >>>>
> > >>>> Thanks for notifying this. But I can't find this patch at patchwork.
> > >>>> I'm not reading fully mail thread, so after reading mails, i will resend at mailing list.
> > >>>
> > >>> Sure, here is the link :)
> > >>> http://lists.denx.de/pipermail/u-boot/2015-August/224566.html
> > >>>
> > >>> Thanks
> > >>> Chin Liang
> > >>>
> > >>>
> > >>>>
> > >>>> Best Regards,
> > >>>> Jaehoon Chung
> > >>>>
> > >>>>>
> > >>>>> Jaehoon, this patch will do a calibration to determine the clksel value.
> > >>>>> Wonder is this something would help or applicable for Exynos? We are
> > >>>>> probing whether this code should go dw_mmc.c instead socfpga_dw_mmc.c.
> > >>>>>
> > >>>>> Thanks
> > >>>>> Chin Liang
> > >>>>>
> > >>>>>> Regards,
> > >>>>>> Simon
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>
> > >>>
> > >>>
> > >>> _______________________________________________
> > >>> U-Boot mailing list
> > >>> U-Boot at lists.denx.de
> > >>> http://lists.denx.de/mailman/listinfo/u-boot
> > >>>
> > >>
> > > 
> > > 
> > > 
> > 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-01  8:54                             ` Chin Liang See
@ 2015-09-01  9:01                               ` Marek Vasut
  2015-09-01  9:10                                 ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-09-01  9:01 UTC (permalink / raw)
  To: u-boot

On Tuesday, September 01, 2015 at 10:54:06 AM, Chin Liang See wrote:
> On Wed, 2015-08-26 at 01:54 -0500, Chin Liang See wrote:
> > On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
> > > On 08/26/2015 02:47 PM, Chin Liang See wrote:
> > > > On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
> > > >> Hi,
> > > >> 
> > > >> On 08/25/2015 12:08 PM, Chin Liang See wrote:
> > > >>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> > > >>>> Hi,
> > > >>>> 
> > > >>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> > > >>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> > > >>>>>> Hi,
> > > >>>>>> 
> > > >>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> 
wrote:
> > > >>>>>>> +CC: Simon Glass
> > > >>>>>>> 
> > > >>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> 
wrote:
> > > >>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See 
wrote:
> > > >>>>>>>>> Hi,
> > > >>>>>>>>> 
> > > >>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> > > >>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See 
wrote:
> > > >>>>>>>>>>> Hi,
> > > >>>>>>>>>> 
> > > >>>>>>>>>> Hi again,
> > > >>>>>>>>>> 
> > > >>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> > > >>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See 
wrote:
> > > >>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting
> > > >>>>>>>>>>>>> for drvsel and smpsel. It will be triggered whenever
> > > >>>>>>>>>>>>> there is a change of card frequency and bus width. This
> > > >>>>>>>>>>>>> is to ensure reliable transmission between the
> > > >>>>>>>>>>>>> controller and the card.
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> > > >>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > > >>>>>>> 
> > > >>>>>>> I think there's something wrong with your git scripts, I did
> > > >>>>>>> not get this email.
> > > >>>>>>> 
> > > >>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> > > >>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> > > >>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> > > >>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> > > >>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> > > >>>>>>>>>>>>> ---
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files
> > > >>>>>>>>>>>>> changed, 180 insertions(+), 7 deletions(-)
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > > >>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c
> > > >>>>>>>>>>>>> 100644 --- a/drivers/mmc/socfpga_dw_mmc.c
> > > >>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> > > >>>>>>>>>>>>> @@ -11,25 +11,140 @@
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
> > > >>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
> > > >>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>> +#include "mmc_private.h"
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>>  static const struct socfpga_clock_manager
> > > >>>>>>>>>>>>>  *clock_manager_base =
> > > >>>>>>>>>>>>>  
> > > >>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> > > >>>>>>>>>>>>>  
> > > >>>>>>>>>>>>>  static const struct socfpga_system_manager
> > > >>>>>>>>>>>>>  *system_manager_base =
> > > >>>>>>>>>>>>>  
> > > >>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host
> > > >>>>>>>>>>>>> *host) +#define CAL_ROWS     7
> > > >>>>>>>>>>>>> +#define CAL_COLS     8
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +/*
> > > >>>>>>>>>>>>> + * This function determines the largest rectangle filled
> > > >>>>>>>>>>>>> with 1's and returns + * the middle. This functon can be
> > > >>>>>>>>>>>>> optimized, for example using the algorithm + * from
> > > >>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-pro
> > > >>>>>>>>>>>>> blem/18441 0529 + * It currently takes less than 1ms,
> > > >>>>>>>>>>>>> while creating the input data takes ~5ms + * so there is
> > > >>>>>>>>>>>>> not a real need to optimize it. + */
> > > >>>>>>>>>>>>> +int find_calibration_point(unsigned char
> > > >>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum,
> > > >>>>>>>>>>>>> unsigned int * cal_row, unsigned int * cal_col)
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>>  {
> > > >>>>>>>>>>>>> 
> > > >>>>>>>>>>>>> -     unsigned int drvsel;
> > > >>>>>>>>>>>>> -     unsigned int smplsel;
> > > >>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
> > > >>>>>>>>>>>>> +     typedef struct
> > > >>>>>>>>>>>>> +     {
> > > >>>>>>>>>>>>> +             unsigned char height;
> > > >>>>>>>>>>>>> +             unsigned char width;
> > > >>>>>>>>>>>>> +             unsigned short area;
> > > >>>>>>>>>>>>> +     } rect_cand_t;
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +     /* Array with the rectangle candidates */
> > > >>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > > >>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
> > > >>>>>>>>>>>>> +     unsigned char height, width, k;
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +     /* No solution if all combinations fail */
> > > >>>>>>>>>>>>> +     if(sum == 0)
> > > >>>>>>>>>>>>> +             return 1;
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
> > > >>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> > > >>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> > > >>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> > > >>>>>>>>>>>>> +             return 0;
> > > >>>>>>>>>>>>> +     }
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +     /*
> > > >>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in
> > > >>>>>>>>>>>>> descending
> > > >>>>>>>> 
> > > >>>>>>>> area
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +      * order
> > > >>>>>>>>>>>>> +      */
> > > >>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> > > >>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ;
> > > >>>>>>>>>>>>> width--){ +                     /* Add a new rectangle
> > > >>>>>>>>>>>>> candidate */ +                    
> > > >>>>>>>>>>>>> rect_cands[cr_rect_cand].height = height; +             
> > > >>>>>>>>>>>>>        rect_cands[cr_rect_cand].width = width; +        
> > > >>>>>>>>>>>>>             rect_cands[cr_rect_cand].area = height *
> > > >>>>>>>>>>>>> width; +                     cr_rect_cand++;
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +                     /* First candidate it always in the
> > > >>>>>>>>>>>>> right
> > > >>>>>>>> 
> > > >>>>>>>> position */
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
> > > >>>>>>>>>>>>> +                             continue;
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +                     /*
> > > >>>>>>>>>>>>> +                      * Put the candidate in right
> > > >>>>>>>>>>>>> location to
> > > >>>>>>>> 
> > > >>>>>>>> maintain
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                      * descending order
> > > >>>>>>>>>>>>> +                      */
> > > >>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1;
> > > >>>>>>>>>>>>> k--){ +                            
> > > >>>>>>>>>>>>> if(rect_cands[k-1].area <
> > > >>>>>>>> 
> > > >>>>>>>> rect_cands[k].area){
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                                     rect_cand_t tmp =
> > > >>>>>>>> 
> > > >>>>>>>> rect_cands[k-1];
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                                     rect_cands[k-1] =
> > > >>>>>>>>>>>>> rect_cands[k]; +                                    
> > > >>>>>>>>>>>>> rect_cands[k] = tmp; +                             }
> > > >>>>>>>>>>>>> else
> > > >>>>>>>>>>>>> +                                     break;
> > > >>>>>>>>>>>>> +                     }
> > > >>>>>>>>>>>>> +             }
> > > >>>>>>>>>>>>> +     }
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in
> > > >>>>>>>>>>>>> descending area order */ +  for(k = 0; k < CAL_ROWS *
> > > >>>>>>>>>>>>> CAL_COLS; k++) { +             unsigned char start_row,
> > > >>>>>>>>>>>>> start_col; +             unsigned rect_width =
> > > >>>>>>>>>>>>> rect_cands[k].width; +             unsigned rect_height
> > > >>>>>>>>>>>>> = rect_cands[k].height; +
> > > >>>>>>>>>>>>> +             /* Find the row and column where the
> > > >>>>>>>>>>>>> candidate fits */ +             for (start_col = 0;
> > > >>>>>>>>>>>>> start_col < (CAL_COLS - rect_width +
> > > >>>>>>>> 
> > > >>>>>>>> 1);
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                  start_col++) {
> > > >>>>>>>>>>>>> +                     for (start_row = 0; start_row <
> > > >>>>>>>>>>>>> (CAL_ROWS - +                          rect_height + 1);
> > > >>>>>>>>>>>>> start_row++) { +                             unsigned ok
> > > >>>>>>>>>>>>> = 1;
> > > >>>>>>>>>>>>> +                             unsigned add_col, add_row;
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +                             /* Determine if the
> > > >>>>>>>>>>>>> rectangle fits here
> > > >>>>>>>> 
> > > >>>>>>>> */
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                             for (add_col = 0; (add_col
> > > >>>>>>>>>>>>> < rect_width)
> > > >>>>>>>> 
> > > >>>>>>>> && ok;
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                                  add_col++) {
> > > >>>>>>>>>>>>> +                                     for (add_row = 0;
> > > >>>>>>>>>>>>> add_row <
> > > >>>>>>>> 
> > > >>>>>>>> rect_height;
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                                          add_row++) {
> > > >>>>>>>>>>>>> +                                             if
> > > >>>>>>>>>>>>> (!cal_results +                                         
> > > >>>>>>>>>>>>>       [start_row+add_row]
> > > >>>>>>>> 
> > > >>>>>>>> [start_col
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                                                +
> > > >>>>>>>>>>>>> add_col]) { +                                           
> > > >>>>>>>>>>>>>          ok = 0; +                                      
> > > >>>>>>>>>>>>>               break; +                                  
> > > >>>>>>>>>>>>>           }
> > > >>>>>>>>>>>>> +                                     }
> > > >>>>>>>>>>>>> +                             }
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +                             /*
> > > >>>>>>>>>>>>> +                              * Return 'middle' of
> > > >>>>>>>>>>>>> rectangle in case
> > > >>>>>>>> 
> > > >>>>>>>> of
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +                              * success
> > > >>>>>>>>>>>>> +                              */
> > > >>>>>>>>>>>>> +                             if (ok) {
> > > >>>>>>>>>>>>> +                                     if(rect_width > 1)
> > > >>>>>>>>>>>>> +                                            
> > > >>>>>>>>>>>>> rect_width--; +
> > > >>>>>>>>>>>>> +                                     if(rect_height > 1)
> > > >>>>>>>>>>>>> +                                            
> > > >>>>>>>>>>>>> rect_height--; +
> > > >>>>>>>>>>>>> +                                     *cal_row =
> > > >>>>>>>>>>>>> start_row + +                                           
> > > >>>>>>>>>>>>>     (rect_height / 2); +                                
> > > >>>>>>>>>>>>>     *cal_col = start_col +
> > > >>>>>>>> 
> > > >>>>>>>> (rect_width / 2);
> > > >>>>>>>> 
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +                                     return 0;
> > > >>>>>>>>>>>>> +                             }
> > > >>>>>>>>>>>>> +                     }
> > > >>>>>>>>>>>>> +             }
> > > >>>>>>>>>>>>> +     }
> > > >>>>>>>>>>>>> +
> > > >>>>>>>>>>>>> +     /* We could not fit any rectangle - return failure
> > > >>>>>>>>>>>>> */ +     return 1;
> > > >>>>>>>>>>>> 
> > > >>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard
> > > >>>>>>>>>>>> return codes ; -EINVAL in this case I believe.
> > > >>>>>>>>>>> 
> > > >>>>>>>>>>> Good suggestion, will fix in v2.
> > > >>>>>>>>>>> Thanks
> > > >>>>>>>>>> 
> > > >>>>>>>>>> Thanks. I was curious, is this really socfpga specific or
> > > >>>>>>>>>> can this calibration be used on dwmmc in general -- thus on
> > > >>>>>>>>>> exynos and rockchip systems -- as well? If it's generic to
> > > >>>>>>>>>> dwmmc, this should be moved into the dwmmc core code. Also,
> > > >>>>>>>>>> I am CCing Simon, he's been plumbing in the DWMMC recently.
> > > >>>>>>> 
> > > >>>>>>> I didn't see you explicitly add Simon to the thread. Doing it
> > > >>>>>>> here..
> > > >>>>>> 
> > > >>>>>> One option is to put the function in the common dw_mmc.c file
> > > >>>>>> but have it be called explicitly by drivers that want it (e.g.
> > > >>>>>> for now, just socfpga). The code you have written does look
> > > >>>>>> generic and perhaps should be used on other platforms,
> > > >>>>>> 
> > > >>>>>>>>> I am not sure. But definitely we can make the calibration
> > > >>>>>>>>> common enough if they required the calibration too. Let wait
> > > >>>>>>>>> feedback from Simon.
> > > >>>>>>> 
> > > >>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA,
> > > >>>>>>> Exynos and Rockchip are using the drvsel and smpsel
> > > >>>>>>> parameters. But I also think these parameters can
> > > >>>>>>> be different for different types of SD card. Are you sure this
> > > >>>>>>> function will cover those
> > > >>>>>>> cases?
> > > >>>>>> 
> > > >>>>>> Not at all, but perhaps that is something we will find out in
> > > >>>>>> the future.
> > > >>>>> 
> > > >>>>> Thanks Simon.
> > > >>>>> 
> > > >>>>> I further checked today and noticed Exynos is setting up the
> > > >>>>> clksel (sample clock and drive clock). But from exynos_dw_mmc.c,
> > > >>>>> the value is coming from device tree. So I am notifying Jaehoon
> > > >>>>> wonder the calibration might applicable for him.
> > > >> 
> > > >> I think this patch should not be common code at all.
> > > >> Of course, it seems that find_calibration_point function can be used
> > > >> at exynos. But it's too complex and not readable.
> > > >> 
> > > >> And smpclk and drvsel are also not common.
> > > >> Depending on SoC, finding approach should be differed.
> > > >> I don't know how smpclk and drvsel controlled, since i don't read
> > > >> TRM of other SoC.
> > > >> 
> > > >> Does it need to find the best clksmpl and drvsel value in
> > > >> bootloader?
> > > > 
> > > > Yah, its little complex as we try to find the best value for 2
> > > > parameters together. Its also due to the nature that we rely on full
> > > > complete transaction cycle to determine pass or fail (drvsel for out
> > > > while clksmp for in).
> > > 
> > > In my experiment, spmlclk value is more important than drvsel.
> > > Anyway, CAL_ROWS and CAL_COLS are candiates, right?
> > 
> > Yup, they are representing the value permutation for smplclk and drvsel.
> > 
> > > If it can be passed by parameter from each SoC dwmmc controller, that
> > > function should be located into dwmmc.c. Because drvsel and smplclk
> > > bits should be difference at each SoC specific register or Generic
> > > dwmmc(UHS_REG_EXT regster).
> > > 
> > > Do you have the plan that change the more generic code than now?
> > 
> > Actually I look back and different SoC have different register location
> > for drvsel and smplclk. They are not located within dwmmc controller
> > registers. As of now, they are configure within the callback function of
> > clksel, I believe that should good.
> 
> For this case, I presume the change would applicable for socfpga only
> instead common dw_mmc. If everyone agreed, I shall send in new revision
> of the patch.

I'm not very convinced that this should be outside of the dw_mmc core.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-01  9:01                               ` Marek Vasut
@ 2015-09-01  9:10                                 ` Chin Liang See
  2015-09-01 10:12                                   ` Jaehoon Chung
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-09-01  9:10 UTC (permalink / raw)
  To: u-boot

On Tue, 2015-09-01 at 11:01 +0200, marex at denx.de wrote:
> On Tuesday, September 01, 2015 at 10:54:06 AM, Chin Liang See wrote:
> > On Wed, 2015-08-26 at 01:54 -0500, Chin Liang See wrote:
> > > On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
> > > > On 08/26/2015 02:47 PM, Chin Liang See wrote:
> > > > > On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
> > > > >> Hi,
> > > > >> 
> > > > >> On 08/25/2015 12:08 PM, Chin Liang See wrote:
> > > > >>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> > > > >>>> Hi,
> > > > >>>> 
> > > > >>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> > > > >>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> > > > >>>>>> Hi,
> > > > >>>>>> 
> > > > >>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> 
> wrote:
> > > > >>>>>>> +CC: Simon Glass
> > > > >>>>>>> 
> > > > >>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> 
> wrote:
> > > > >>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See 
> wrote:
> > > > >>>>>>>>> Hi,
> > > > >>>>>>>>> 
> > > > >>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> > > > >>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See 
> wrote:
> > > > >>>>>>>>>>> Hi,
> > > > >>>>>>>>>> 
> > > > >>>>>>>>>> Hi again,
> > > > >>>>>>>>>> 
> > > > >>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> > > > >>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See 
> wrote:
> > > > >>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting
> > > > >>>>>>>>>>>>> for drvsel and smpsel. It will be triggered whenever
> > > > >>>>>>>>>>>>> there is a change of card frequency and bus width. This
> > > > >>>>>>>>>>>>> is to ensure reliable transmission between the
> > > > >>>>>>>>>>>>> controller and the card.
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> > > > >>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > > > >>>>>>> 
> > > > >>>>>>> I think there's something wrong with your git scripts, I did
> > > > >>>>>>> not get this email.
> > > > >>>>>>> 
> > > > >>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> > > > >>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> > > > >>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> > > > >>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> > > > >>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> > > > >>>>>>>>>>>>> ---
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files
> > > > >>>>>>>>>>>>> changed, 180 insertions(+), 7 deletions(-)
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > > > >>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c
> > > > >>>>>>>>>>>>> 100644 --- a/drivers/mmc/socfpga_dw_mmc.c
> > > > >>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> > > > >>>>>>>>>>>>> @@ -11,25 +11,140 @@
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
> > > > >>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
> > > > >>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>> +#include "mmc_private.h"
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>>  static const struct socfpga_clock_manager
> > > > >>>>>>>>>>>>>  *clock_manager_base =
> > > > >>>>>>>>>>>>>  
> > > > >>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> > > > >>>>>>>>>>>>>  
> > > > >>>>>>>>>>>>>  static const struct socfpga_system_manager
> > > > >>>>>>>>>>>>>  *system_manager_base =
> > > > >>>>>>>>>>>>>  
> > > > >>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host
> > > > >>>>>>>>>>>>> *host) +#define CAL_ROWS     7
> > > > >>>>>>>>>>>>> +#define CAL_COLS     8
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +/*
> > > > >>>>>>>>>>>>> + * This function determines the largest rectangle filled
> > > > >>>>>>>>>>>>> with 1's and returns + * the middle. This functon can be
> > > > >>>>>>>>>>>>> optimized, for example using the algorithm + * from
> > > > >>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-pro
> > > > >>>>>>>>>>>>> blem/18441 0529 + * It currently takes less than 1ms,
> > > > >>>>>>>>>>>>> while creating the input data takes ~5ms + * so there is
> > > > >>>>>>>>>>>>> not a real need to optimize it. + */
> > > > >>>>>>>>>>>>> +int find_calibration_point(unsigned char
> > > > >>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum,
> > > > >>>>>>>>>>>>> unsigned int * cal_row, unsigned int * cal_col)
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>>  {
> > > > >>>>>>>>>>>>> 
> > > > >>>>>>>>>>>>> -     unsigned int drvsel;
> > > > >>>>>>>>>>>>> -     unsigned int smplsel;
> > > > >>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
> > > > >>>>>>>>>>>>> +     typedef struct
> > > > >>>>>>>>>>>>> +     {
> > > > >>>>>>>>>>>>> +             unsigned char height;
> > > > >>>>>>>>>>>>> +             unsigned char width;
> > > > >>>>>>>>>>>>> +             unsigned short area;
> > > > >>>>>>>>>>>>> +     } rect_cand_t;
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +     /* Array with the rectangle candidates */
> > > > >>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > > > >>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
> > > > >>>>>>>>>>>>> +     unsigned char height, width, k;
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +     /* No solution if all combinations fail */
> > > > >>>>>>>>>>>>> +     if(sum == 0)
> > > > >>>>>>>>>>>>> +             return 1;
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
> > > > >>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> > > > >>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> > > > >>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> > > > >>>>>>>>>>>>> +             return 0;
> > > > >>>>>>>>>>>>> +     }
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +     /*
> > > > >>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in
> > > > >>>>>>>>>>>>> descending
> > > > >>>>>>>> 
> > > > >>>>>>>> area
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +      * order
> > > > >>>>>>>>>>>>> +      */
> > > > >>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> > > > >>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ;
> > > > >>>>>>>>>>>>> width--){ +                     /* Add a new rectangle
> > > > >>>>>>>>>>>>> candidate */ +                    
> > > > >>>>>>>>>>>>> rect_cands[cr_rect_cand].height = height; +             
> > > > >>>>>>>>>>>>>        rect_cands[cr_rect_cand].width = width; +        
> > > > >>>>>>>>>>>>>             rect_cands[cr_rect_cand].area = height *
> > > > >>>>>>>>>>>>> width; +                     cr_rect_cand++;
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +                     /* First candidate it always in the
> > > > >>>>>>>>>>>>> right
> > > > >>>>>>>> 
> > > > >>>>>>>> position */
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
> > > > >>>>>>>>>>>>> +                             continue;
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +                     /*
> > > > >>>>>>>>>>>>> +                      * Put the candidate in right
> > > > >>>>>>>>>>>>> location to
> > > > >>>>>>>> 
> > > > >>>>>>>> maintain
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                      * descending order
> > > > >>>>>>>>>>>>> +                      */
> > > > >>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1;
> > > > >>>>>>>>>>>>> k--){ +                            
> > > > >>>>>>>>>>>>> if(rect_cands[k-1].area <
> > > > >>>>>>>> 
> > > > >>>>>>>> rect_cands[k].area){
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                                     rect_cand_t tmp =
> > > > >>>>>>>> 
> > > > >>>>>>>> rect_cands[k-1];
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                                     rect_cands[k-1] =
> > > > >>>>>>>>>>>>> rect_cands[k]; +                                    
> > > > >>>>>>>>>>>>> rect_cands[k] = tmp; +                             }
> > > > >>>>>>>>>>>>> else
> > > > >>>>>>>>>>>>> +                                     break;
> > > > >>>>>>>>>>>>> +                     }
> > > > >>>>>>>>>>>>> +             }
> > > > >>>>>>>>>>>>> +     }
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in
> > > > >>>>>>>>>>>>> descending area order */ +  for(k = 0; k < CAL_ROWS *
> > > > >>>>>>>>>>>>> CAL_COLS; k++) { +             unsigned char start_row,
> > > > >>>>>>>>>>>>> start_col; +             unsigned rect_width =
> > > > >>>>>>>>>>>>> rect_cands[k].width; +             unsigned rect_height
> > > > >>>>>>>>>>>>> = rect_cands[k].height; +
> > > > >>>>>>>>>>>>> +             /* Find the row and column where the
> > > > >>>>>>>>>>>>> candidate fits */ +             for (start_col = 0;
> > > > >>>>>>>>>>>>> start_col < (CAL_COLS - rect_width +
> > > > >>>>>>>> 
> > > > >>>>>>>> 1);
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                  start_col++) {
> > > > >>>>>>>>>>>>> +                     for (start_row = 0; start_row <
> > > > >>>>>>>>>>>>> (CAL_ROWS - +                          rect_height + 1);
> > > > >>>>>>>>>>>>> start_row++) { +                             unsigned ok
> > > > >>>>>>>>>>>>> = 1;
> > > > >>>>>>>>>>>>> +                             unsigned add_col, add_row;
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +                             /* Determine if the
> > > > >>>>>>>>>>>>> rectangle fits here
> > > > >>>>>>>> 
> > > > >>>>>>>> */
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                             for (add_col = 0; (add_col
> > > > >>>>>>>>>>>>> < rect_width)
> > > > >>>>>>>> 
> > > > >>>>>>>> && ok;
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                                  add_col++) {
> > > > >>>>>>>>>>>>> +                                     for (add_row = 0;
> > > > >>>>>>>>>>>>> add_row <
> > > > >>>>>>>> 
> > > > >>>>>>>> rect_height;
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                                          add_row++) {
> > > > >>>>>>>>>>>>> +                                             if
> > > > >>>>>>>>>>>>> (!cal_results +                                         
> > > > >>>>>>>>>>>>>       [start_row+add_row]
> > > > >>>>>>>> 
> > > > >>>>>>>> [start_col
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                                                +
> > > > >>>>>>>>>>>>> add_col]) { +                                           
> > > > >>>>>>>>>>>>>          ok = 0; +                                      
> > > > >>>>>>>>>>>>>               break; +                                  
> > > > >>>>>>>>>>>>>           }
> > > > >>>>>>>>>>>>> +                                     }
> > > > >>>>>>>>>>>>> +                             }
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +                             /*
> > > > >>>>>>>>>>>>> +                              * Return 'middle' of
> > > > >>>>>>>>>>>>> rectangle in case
> > > > >>>>>>>> 
> > > > >>>>>>>> of
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +                              * success
> > > > >>>>>>>>>>>>> +                              */
> > > > >>>>>>>>>>>>> +                             if (ok) {
> > > > >>>>>>>>>>>>> +                                     if(rect_width > 1)
> > > > >>>>>>>>>>>>> +                                            
> > > > >>>>>>>>>>>>> rect_width--; +
> > > > >>>>>>>>>>>>> +                                     if(rect_height > 1)
> > > > >>>>>>>>>>>>> +                                            
> > > > >>>>>>>>>>>>> rect_height--; +
> > > > >>>>>>>>>>>>> +                                     *cal_row =
> > > > >>>>>>>>>>>>> start_row + +                                           
> > > > >>>>>>>>>>>>>     (rect_height / 2); +                                
> > > > >>>>>>>>>>>>>     *cal_col = start_col +
> > > > >>>>>>>> 
> > > > >>>>>>>> (rect_width / 2);
> > > > >>>>>>>> 
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +                                     return 0;
> > > > >>>>>>>>>>>>> +                             }
> > > > >>>>>>>>>>>>> +                     }
> > > > >>>>>>>>>>>>> +             }
> > > > >>>>>>>>>>>>> +     }
> > > > >>>>>>>>>>>>> +
> > > > >>>>>>>>>>>>> +     /* We could not fit any rectangle - return failure
> > > > >>>>>>>>>>>>> */ +     return 1;
> > > > >>>>>>>>>>>> 
> > > > >>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard
> > > > >>>>>>>>>>>> return codes ; -EINVAL in this case I believe.
> > > > >>>>>>>>>>> 
> > > > >>>>>>>>>>> Good suggestion, will fix in v2.
> > > > >>>>>>>>>>> Thanks
> > > > >>>>>>>>>> 
> > > > >>>>>>>>>> Thanks. I was curious, is this really socfpga specific or
> > > > >>>>>>>>>> can this calibration be used on dwmmc in general -- thus on
> > > > >>>>>>>>>> exynos and rockchip systems -- as well? If it's generic to
> > > > >>>>>>>>>> dwmmc, this should be moved into the dwmmc core code. Also,
> > > > >>>>>>>>>> I am CCing Simon, he's been plumbing in the DWMMC recently.
> > > > >>>>>>> 
> > > > >>>>>>> I didn't see you explicitly add Simon to the thread. Doing it
> > > > >>>>>>> here..
> > > > >>>>>> 
> > > > >>>>>> One option is to put the function in the common dw_mmc.c file
> > > > >>>>>> but have it be called explicitly by drivers that want it (e.g.
> > > > >>>>>> for now, just socfpga). The code you have written does look
> > > > >>>>>> generic and perhaps should be used on other platforms,
> > > > >>>>>> 
> > > > >>>>>>>>> I am not sure. But definitely we can make the calibration
> > > > >>>>>>>>> common enough if they required the calibration too. Let wait
> > > > >>>>>>>>> feedback from Simon.
> > > > >>>>>>> 
> > > > >>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA,
> > > > >>>>>>> Exynos and Rockchip are using the drvsel and smpsel
> > > > >>>>>>> parameters. But I also think these parameters can
> > > > >>>>>>> be different for different types of SD card. Are you sure this
> > > > >>>>>>> function will cover those
> > > > >>>>>>> cases?
> > > > >>>>>> 
> > > > >>>>>> Not at all, but perhaps that is something we will find out in
> > > > >>>>>> the future.
> > > > >>>>> 
> > > > >>>>> Thanks Simon.
> > > > >>>>> 
> > > > >>>>> I further checked today and noticed Exynos is setting up the
> > > > >>>>> clksel (sample clock and drive clock). But from exynos_dw_mmc.c,
> > > > >>>>> the value is coming from device tree. So I am notifying Jaehoon
> > > > >>>>> wonder the calibration might applicable for him.
> > > > >> 
> > > > >> I think this patch should not be common code at all.
> > > > >> Of course, it seems that find_calibration_point function can be used
> > > > >> at exynos. But it's too complex and not readable.
> > > > >> 
> > > > >> And smpclk and drvsel are also not common.
> > > > >> Depending on SoC, finding approach should be differed.
> > > > >> I don't know how smpclk and drvsel controlled, since i don't read
> > > > >> TRM of other SoC.
> > > > >> 
> > > > >> Does it need to find the best clksmpl and drvsel value in
> > > > >> bootloader?
> > > > > 
> > > > > Yah, its little complex as we try to find the best value for 2
> > > > > parameters together. Its also due to the nature that we rely on full
> > > > > complete transaction cycle to determine pass or fail (drvsel for out
> > > > > while clksmp for in).
> > > > 
> > > > In my experiment, spmlclk value is more important than drvsel.
> > > > Anyway, CAL_ROWS and CAL_COLS are candiates, right?
> > > 
> > > Yup, they are representing the value permutation for smplclk and drvsel.
> > > 
> > > > If it can be passed by parameter from each SoC dwmmc controller, that
> > > > function should be located into dwmmc.c. Because drvsel and smplclk
> > > > bits should be difference at each SoC specific register or Generic
> > > > dwmmc(UHS_REG_EXT regster).
> > > > 
> > > > Do you have the plan that change the more generic code than now?
> > > 
> > > Actually I look back and different SoC have different register location
> > > for drvsel and smplclk. They are not located within dwmmc controller
> > > registers. As of now, they are configure within the callback function of
> > > clksel, I believe that should good.
> > 
> > For this case, I presume the change would applicable for socfpga only
> > instead common dw_mmc. If everyone agreed, I shall send in new revision
> > of the patch.
> 
> I'm not very convinced that this should be outside of the dw_mmc core.

Would want to hear more from Jaehoon as Exynos and SOCFPGA are the one
setting up these values.

Thanks
Chin Liang

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-01  9:10                                 ` Chin Liang See
@ 2015-09-01 10:12                                   ` Jaehoon Chung
  2015-09-01 14:53                                     ` Dinh Nguyen
  0 siblings, 1 reply; 40+ messages in thread
From: Jaehoon Chung @ 2015-09-01 10:12 UTC (permalink / raw)
  To: u-boot

On 09/01/2015 06:10 PM, Chin Liang See wrote:
> On Tue, 2015-09-01 at 11:01 +0200, marex at denx.de wrote:
>> On Tuesday, September 01, 2015 at 10:54:06 AM, Chin Liang See wrote:
>>> On Wed, 2015-08-26 at 01:54 -0500, Chin Liang See wrote:
>>>> On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
>>>>> On 08/26/2015 02:47 PM, Chin Liang See wrote:
>>>>>> On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> On 08/25/2015 12:08 PM, Chin Liang See wrote:
>>>>>>>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
>>>>>>>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> 
>> wrote:
>>>>>>>>>>>> +CC: Simon Glass
>>>>>>>>>>>>
>>>>>>>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> 
>> wrote:
>>>>>>>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See 
>> wrote:
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See 
>> wrote:
>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi again,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>>>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See 
>> wrote:
>>>>>>>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting
>>>>>>>>>>>>>>>>>> for drvsel and smpsel. It will be triggered whenever
>>>>>>>>>>>>>>>>>> there is a change of card frequency and bus width. This
>>>>>>>>>>>>>>>>>> is to ensure reliable transmission between the
>>>>>>>>>>>>>>>>>> controller and the card.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
>>>>>>>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
>>>>>>>>>>>>
>>>>>>>>>>>> I think there's something wrong with your git scripts, I did
>>>>>>>>>>>> not get this email.
>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
>>>>>>>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
>>>>>>>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
>>>>>>>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
>>>>>>>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files
>>>>>>>>>>>>>>>>>> changed, 180 insertions(+), 7 deletions(-)
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c
>>>>>>>>>>>>>>>>>> 100644 --- a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>>>>>>> @@ -11,25 +11,140 @@
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
>>>>>>>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
>>>>>>>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +#include "mmc_private.h"
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>  static const struct socfpga_clock_manager
>>>>>>>>>>>>>>>>>>  *clock_manager_base =
>>>>>>>>>>>>>>>>>>  
>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
>>>>>>>>>>>>>>>>>>  
>>>>>>>>>>>>>>>>>>  static const struct socfpga_system_manager
>>>>>>>>>>>>>>>>>>  *system_manager_base =
>>>>>>>>>>>>>>>>>>  
>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host
>>>>>>>>>>>>>>>>>> *host) +#define CAL_ROWS     7
>>>>>>>>>>>>>>>>>> +#define CAL_COLS     8
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +/*
>>>>>>>>>>>>>>>>>> + * This function determines the largest rectangle filled
>>>>>>>>>>>>>>>>>> with 1's and returns + * the middle. This functon can be
>>>>>>>>>>>>>>>>>> optimized, for example using the algorithm + * from
>>>>>>>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-pro
>>>>>>>>>>>>>>>>>> blem/18441 0529 + * It currently takes less than 1ms,
>>>>>>>>>>>>>>>>>> while creating the input data takes ~5ms + * so there is
>>>>>>>>>>>>>>>>>> not a real need to optimize it. + */
>>>>>>>>>>>>>>>>>> +int find_calibration_point(unsigned char
>>>>>>>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum,
>>>>>>>>>>>>>>>>>> unsigned int * cal_row, unsigned int * cal_col)
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>  {
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> -     unsigned int drvsel;
>>>>>>>>>>>>>>>>>> -     unsigned int smplsel;
>>>>>>>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
>>>>>>>>>>>>>>>>>> +     typedef struct
>>>>>>>>>>>>>>>>>> +     {
>>>>>>>>>>>>>>>>>> +             unsigned char height;
>>>>>>>>>>>>>>>>>> +             unsigned char width;
>>>>>>>>>>>>>>>>>> +             unsigned short area;
>>>>>>>>>>>>>>>>>> +     } rect_cand_t;
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +     /* Array with the rectangle candidates */
>>>>>>>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
>>>>>>>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
>>>>>>>>>>>>>>>>>> +     unsigned char height, width, k;
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +     /* No solution if all combinations fail */
>>>>>>>>>>>>>>>>>> +     if(sum == 0)
>>>>>>>>>>>>>>>>>> +             return 1;
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
>>>>>>>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
>>>>>>>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
>>>>>>>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
>>>>>>>>>>>>>>>>>> +             return 0;
>>>>>>>>>>>>>>>>>> +     }
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +     /*
>>>>>>>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in
>>>>>>>>>>>>>>>>>> descending
>>>>>>>>>>>>>
>>>>>>>>>>>>> area
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +      * order
>>>>>>>>>>>>>>>>>> +      */
>>>>>>>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
>>>>>>>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ;
>>>>>>>>>>>>>>>>>> width--){ +                     /* Add a new rectangle
>>>>>>>>>>>>>>>>>> candidate */ +                    
>>>>>>>>>>>>>>>>>> rect_cands[cr_rect_cand].height = height; +             
>>>>>>>>>>>>>>>>>>        rect_cands[cr_rect_cand].width = width; +        
>>>>>>>>>>>>>>>>>>             rect_cands[cr_rect_cand].area = height *
>>>>>>>>>>>>>>>>>> width; +                     cr_rect_cand++;
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +                     /* First candidate it always in the
>>>>>>>>>>>>>>>>>> right
>>>>>>>>>>>>>
>>>>>>>>>>>>> position */
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
>>>>>>>>>>>>>>>>>> +                             continue;
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +                     /*
>>>>>>>>>>>>>>>>>> +                      * Put the candidate in right
>>>>>>>>>>>>>>>>>> location to
>>>>>>>>>>>>>
>>>>>>>>>>>>> maintain
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                      * descending order
>>>>>>>>>>>>>>>>>> +                      */
>>>>>>>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1;
>>>>>>>>>>>>>>>>>> k--){ +                            
>>>>>>>>>>>>>>>>>> if(rect_cands[k-1].area <
>>>>>>>>>>>>>
>>>>>>>>>>>>> rect_cands[k].area){
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                                     rect_cand_t tmp =
>>>>>>>>>>>>>
>>>>>>>>>>>>> rect_cands[k-1];
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                                     rect_cands[k-1] =
>>>>>>>>>>>>>>>>>> rect_cands[k]; +                                    
>>>>>>>>>>>>>>>>>> rect_cands[k] = tmp; +                             }
>>>>>>>>>>>>>>>>>> else
>>>>>>>>>>>>>>>>>> +                                     break;
>>>>>>>>>>>>>>>>>> +                     }
>>>>>>>>>>>>>>>>>> +             }
>>>>>>>>>>>>>>>>>> +     }
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in
>>>>>>>>>>>>>>>>>> descending area order */ +  for(k = 0; k < CAL_ROWS *
>>>>>>>>>>>>>>>>>> CAL_COLS; k++) { +             unsigned char start_row,
>>>>>>>>>>>>>>>>>> start_col; +             unsigned rect_width =
>>>>>>>>>>>>>>>>>> rect_cands[k].width; +             unsigned rect_height
>>>>>>>>>>>>>>>>>> = rect_cands[k].height; +
>>>>>>>>>>>>>>>>>> +             /* Find the row and column where the
>>>>>>>>>>>>>>>>>> candidate fits */ +             for (start_col = 0;
>>>>>>>>>>>>>>>>>> start_col < (CAL_COLS - rect_width +
>>>>>>>>>>>>>
>>>>>>>>>>>>> 1);
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                  start_col++) {
>>>>>>>>>>>>>>>>>> +                     for (start_row = 0; start_row <
>>>>>>>>>>>>>>>>>> (CAL_ROWS - +                          rect_height + 1);
>>>>>>>>>>>>>>>>>> start_row++) { +                             unsigned ok
>>>>>>>>>>>>>>>>>> = 1;
>>>>>>>>>>>>>>>>>> +                             unsigned add_col, add_row;
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +                             /* Determine if the
>>>>>>>>>>>>>>>>>> rectangle fits here
>>>>>>>>>>>>>
>>>>>>>>>>>>> */
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                             for (add_col = 0; (add_col
>>>>>>>>>>>>>>>>>> < rect_width)
>>>>>>>>>>>>>
>>>>>>>>>>>>> && ok;
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                                  add_col++) {
>>>>>>>>>>>>>>>>>> +                                     for (add_row = 0;
>>>>>>>>>>>>>>>>>> add_row <
>>>>>>>>>>>>>
>>>>>>>>>>>>> rect_height;
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                                          add_row++) {
>>>>>>>>>>>>>>>>>> +                                             if
>>>>>>>>>>>>>>>>>> (!cal_results +                                         
>>>>>>>>>>>>>>>>>>       [start_row+add_row]
>>>>>>>>>>>>>
>>>>>>>>>>>>> [start_col
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                                                +
>>>>>>>>>>>>>>>>>> add_col]) { +                                           
>>>>>>>>>>>>>>>>>>          ok = 0; +                                      
>>>>>>>>>>>>>>>>>>               break; +                                  
>>>>>>>>>>>>>>>>>>           }
>>>>>>>>>>>>>>>>>> +                                     }
>>>>>>>>>>>>>>>>>> +                             }
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +                             /*
>>>>>>>>>>>>>>>>>> +                              * Return 'middle' of
>>>>>>>>>>>>>>>>>> rectangle in case
>>>>>>>>>>>>>
>>>>>>>>>>>>> of
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +                              * success
>>>>>>>>>>>>>>>>>> +                              */
>>>>>>>>>>>>>>>>>> +                             if (ok) {
>>>>>>>>>>>>>>>>>> +                                     if(rect_width > 1)
>>>>>>>>>>>>>>>>>> +                                            
>>>>>>>>>>>>>>>>>> rect_width--; +
>>>>>>>>>>>>>>>>>> +                                     if(rect_height > 1)
>>>>>>>>>>>>>>>>>> +                                            
>>>>>>>>>>>>>>>>>> rect_height--; +
>>>>>>>>>>>>>>>>>> +                                     *cal_row =
>>>>>>>>>>>>>>>>>> start_row + +                                           
>>>>>>>>>>>>>>>>>>     (rect_height / 2); +                                
>>>>>>>>>>>>>>>>>>     *cal_col = start_col +
>>>>>>>>>>>>>
>>>>>>>>>>>>> (rect_width / 2);
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +                                     return 0;
>>>>>>>>>>>>>>>>>> +                             }
>>>>>>>>>>>>>>>>>> +                     }
>>>>>>>>>>>>>>>>>> +             }
>>>>>>>>>>>>>>>>>> +     }
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +     /* We could not fit any rectangle - return failure
>>>>>>>>>>>>>>>>>> */ +     return 1;
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard
>>>>>>>>>>>>>>>>> return codes ; -EINVAL in this case I believe.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Good suggestion, will fix in v2.
>>>>>>>>>>>>>>>> Thanks
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Thanks. I was curious, is this really socfpga specific or
>>>>>>>>>>>>>>> can this calibration be used on dwmmc in general -- thus on
>>>>>>>>>>>>>>> exynos and rockchip systems -- as well? If it's generic to
>>>>>>>>>>>>>>> dwmmc, this should be moved into the dwmmc core code. Also,
>>>>>>>>>>>>>>> I am CCing Simon, he's been plumbing in the DWMMC recently.
>>>>>>>>>>>>
>>>>>>>>>>>> I didn't see you explicitly add Simon to the thread. Doing it
>>>>>>>>>>>> here..
>>>>>>>>>>>
>>>>>>>>>>> One option is to put the function in the common dw_mmc.c file
>>>>>>>>>>> but have it be called explicitly by drivers that want it (e.g.
>>>>>>>>>>> for now, just socfpga). The code you have written does look
>>>>>>>>>>> generic and perhaps should be used on other platforms,
>>>>>>>>>>>
>>>>>>>>>>>>>> I am not sure. But definitely we can make the calibration
>>>>>>>>>>>>>> common enough if they required the calibration too. Let wait
>>>>>>>>>>>>>> feedback from Simon.
>>>>>>>>>>>>
>>>>>>>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA,
>>>>>>>>>>>> Exynos and Rockchip are using the drvsel and smpsel
>>>>>>>>>>>> parameters. But I also think these parameters can
>>>>>>>>>>>> be different for different types of SD card. Are you sure this
>>>>>>>>>>>> function will cover those
>>>>>>>>>>>> cases?
>>>>>>>>>>>
>>>>>>>>>>> Not at all, but perhaps that is something we will find out in
>>>>>>>>>>> the future.
>>>>>>>>>>
>>>>>>>>>> Thanks Simon.
>>>>>>>>>>
>>>>>>>>>> I further checked today and noticed Exynos is setting up the
>>>>>>>>>> clksel (sample clock and drive clock). But from exynos_dw_mmc.c,
>>>>>>>>>> the value is coming from device tree. So I am notifying Jaehoon
>>>>>>>>>> wonder the calibration might applicable for him.
>>>>>>>
>>>>>>> I think this patch should not be common code at all.
>>>>>>> Of course, it seems that find_calibration_point function can be used
>>>>>>> at exynos. But it's too complex and not readable.
>>>>>>>
>>>>>>> And smpclk and drvsel are also not common.
>>>>>>> Depending on SoC, finding approach should be differed.
>>>>>>> I don't know how smpclk and drvsel controlled, since i don't read
>>>>>>> TRM of other SoC.
>>>>>>>
>>>>>>> Does it need to find the best clksmpl and drvsel value in
>>>>>>> bootloader?
>>>>>>
>>>>>> Yah, its little complex as we try to find the best value for 2
>>>>>> parameters together. Its also due to the nature that we rely on full
>>>>>> complete transaction cycle to determine pass or fail (drvsel for out
>>>>>> while clksmp for in).
>>>>>
>>>>> In my experiment, spmlclk value is more important than drvsel.
>>>>> Anyway, CAL_ROWS and CAL_COLS are candiates, right?
>>>>
>>>> Yup, they are representing the value permutation for smplclk and drvsel.
>>>>
>>>>> If it can be passed by parameter from each SoC dwmmc controller, that
>>>>> function should be located into dwmmc.c. Because drvsel and smplclk
>>>>> bits should be difference at each SoC specific register or Generic
>>>>> dwmmc(UHS_REG_EXT regster).
>>>>>
>>>>> Do you have the plan that change the more generic code than now?
>>>>
>>>> Actually I look back and different SoC have different register location
>>>> for drvsel and smplclk. They are not located within dwmmc controller
>>>> registers. As of now, they are configure within the callback function of
>>>> clksel, I believe that should good.
>>>
>>> For this case, I presume the change would applicable for socfpga only
>>> instead common dw_mmc. If everyone agreed, I shall send in new revision
>>> of the patch.
>>
>> I'm not very convinced that this should be outside of the dw_mmc core.
> 
> Would want to hear more from Jaehoon as Exynos and SOCFPGA are the one
> setting up these values.

Since this approach is not based on dwmmc TRM, it's based on SOCFPGA SoC,
i think that it doesn't need to include into dwmmc core.
If need to located into dwmmc core, this code needs to modify more.

As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not core feature.
Other SoC can't be used them. we don't know.


Best Regards,
Jaehoon Chung

> 
> Thanks
> Chin Liang
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-01 10:12                                   ` Jaehoon Chung
@ 2015-09-01 14:53                                     ` Dinh Nguyen
  2015-09-02 10:32                                       ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Dinh Nguyen @ 2015-09-01 14:53 UTC (permalink / raw)
  To: u-boot

On 09/01/2015 05:12 AM, Jaehoon Chung wrote:
> On 09/01/2015 06:10 PM, Chin Liang See wrote:
>> On Tue, 2015-09-01 at 11:01 +0200, marex at denx.de wrote:
>>> On Tuesday, September 01, 2015 at 10:54:06 AM, Chin Liang See wrote:
>>>> On Wed, 2015-08-26 at 01:54 -0500, Chin Liang See wrote:
>>>>> On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
>>>>>> On 08/26/2015 02:47 PM, Chin Liang See wrote:
>>>>>>> On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On 08/25/2015 12:08 PM, Chin Liang See wrote:
>>>>>>>>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
>>>>>>>>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com> 
>>> wrote:
>>>>>>>>>>>>> +CC: Simon Glass
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de> 
>>> wrote:
>>>>>>>>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See 
>>> wrote:
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
>>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang See 
>>> wrote:
>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi again,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
>>>>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang See 
>>> wrote:
>>>>>>>>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting
>>>>>>>>>>>>>>>>>>> for drvsel and smpsel. It will be triggered whenever
>>>>>>>>>>>>>>>>>>> there is a change of card frequency and bus width. This
>>>>>>>>>>>>>>>>>>> is to ensure reliable transmission between the
>>>>>>>>>>>>>>>>>>> controller and the card.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
>>>>>>>>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
>>>>>>>>>>>>>
>>>>>>>>>>>>> I think there's something wrong with your git scripts, I did
>>>>>>>>>>>>> not get this email.
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
>>>>>>>>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
>>>>>>>>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
>>>>>>>>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
>>>>>>>>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files
>>>>>>>>>>>>>>>>>>> changed, 180 insertions(+), 7 deletions(-)
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c
>>>>>>>>>>>>>>>>>>> 100644 --- a/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
>>>>>>>>>>>>>>>>>>> @@ -11,25 +11,140 @@
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
>>>>>>>>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
>>>>>>>>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +#include "mmc_private.h"
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>  static const struct socfpga_clock_manager
>>>>>>>>>>>>>>>>>>>  *clock_manager_base =
>>>>>>>>>>>>>>>>>>>  
>>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
>>>>>>>>>>>>>>>>>>>  
>>>>>>>>>>>>>>>>>>>  static const struct socfpga_system_manager
>>>>>>>>>>>>>>>>>>>  *system_manager_base =
>>>>>>>>>>>>>>>>>>>  
>>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host
>>>>>>>>>>>>>>>>>>> *host) +#define CAL_ROWS     7
>>>>>>>>>>>>>>>>>>> +#define CAL_COLS     8
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +/*
>>>>>>>>>>>>>>>>>>> + * This function determines the largest rectangle filled
>>>>>>>>>>>>>>>>>>> with 1's and returns + * the middle. This functon can be
>>>>>>>>>>>>>>>>>>> optimized, for example using the algorithm + * from
>>>>>>>>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-pro
>>>>>>>>>>>>>>>>>>> blem/18441 0529 + * It currently takes less than 1ms,
>>>>>>>>>>>>>>>>>>> while creating the input data takes ~5ms + * so there is
>>>>>>>>>>>>>>>>>>> not a real need to optimize it. + */
>>>>>>>>>>>>>>>>>>> +int find_calibration_point(unsigned char
>>>>>>>>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum,
>>>>>>>>>>>>>>>>>>> unsigned int * cal_row, unsigned int * cal_col)
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>  {
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> -     unsigned int drvsel;
>>>>>>>>>>>>>>>>>>> -     unsigned int smplsel;
>>>>>>>>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
>>>>>>>>>>>>>>>>>>> +     typedef struct
>>>>>>>>>>>>>>>>>>> +     {
>>>>>>>>>>>>>>>>>>> +             unsigned char height;
>>>>>>>>>>>>>>>>>>> +             unsigned char width;
>>>>>>>>>>>>>>>>>>> +             unsigned short area;
>>>>>>>>>>>>>>>>>>> +     } rect_cand_t;
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +     /* Array with the rectangle candidates */
>>>>>>>>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
>>>>>>>>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
>>>>>>>>>>>>>>>>>>> +     unsigned char height, width, k;
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +     /* No solution if all combinations fail */
>>>>>>>>>>>>>>>>>>> +     if(sum == 0)
>>>>>>>>>>>>>>>>>>> +             return 1;
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
>>>>>>>>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
>>>>>>>>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
>>>>>>>>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
>>>>>>>>>>>>>>>>>>> +             return 0;
>>>>>>>>>>>>>>>>>>> +     }
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +     /*
>>>>>>>>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in
>>>>>>>>>>>>>>>>>>> descending
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> area
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +      * order
>>>>>>>>>>>>>>>>>>> +      */
>>>>>>>>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
>>>>>>>>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ;
>>>>>>>>>>>>>>>>>>> width--){ +                     /* Add a new rectangle
>>>>>>>>>>>>>>>>>>> candidate */ +                    
>>>>>>>>>>>>>>>>>>> rect_cands[cr_rect_cand].height = height; +             
>>>>>>>>>>>>>>>>>>>        rect_cands[cr_rect_cand].width = width; +        
>>>>>>>>>>>>>>>>>>>             rect_cands[cr_rect_cand].area = height *
>>>>>>>>>>>>>>>>>>> width; +                     cr_rect_cand++;
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +                     /* First candidate it always in the
>>>>>>>>>>>>>>>>>>> right
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> position */
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
>>>>>>>>>>>>>>>>>>> +                             continue;
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +                     /*
>>>>>>>>>>>>>>>>>>> +                      * Put the candidate in right
>>>>>>>>>>>>>>>>>>> location to
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> maintain
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                      * descending order
>>>>>>>>>>>>>>>>>>> +                      */
>>>>>>>>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1;
>>>>>>>>>>>>>>>>>>> k--){ +                            
>>>>>>>>>>>>>>>>>>> if(rect_cands[k-1].area <
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> rect_cands[k].area){
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                                     rect_cand_t tmp =
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> rect_cands[k-1];
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                                     rect_cands[k-1] =
>>>>>>>>>>>>>>>>>>> rect_cands[k]; +                                    
>>>>>>>>>>>>>>>>>>> rect_cands[k] = tmp; +                             }
>>>>>>>>>>>>>>>>>>> else
>>>>>>>>>>>>>>>>>>> +                                     break;
>>>>>>>>>>>>>>>>>>> +                     }
>>>>>>>>>>>>>>>>>>> +             }
>>>>>>>>>>>>>>>>>>> +     }
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in
>>>>>>>>>>>>>>>>>>> descending area order */ +  for(k = 0; k < CAL_ROWS *
>>>>>>>>>>>>>>>>>>> CAL_COLS; k++) { +             unsigned char start_row,
>>>>>>>>>>>>>>>>>>> start_col; +             unsigned rect_width =
>>>>>>>>>>>>>>>>>>> rect_cands[k].width; +             unsigned rect_height
>>>>>>>>>>>>>>>>>>> = rect_cands[k].height; +
>>>>>>>>>>>>>>>>>>> +             /* Find the row and column where the
>>>>>>>>>>>>>>>>>>> candidate fits */ +             for (start_col = 0;
>>>>>>>>>>>>>>>>>>> start_col < (CAL_COLS - rect_width +
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 1);
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                  start_col++) {
>>>>>>>>>>>>>>>>>>> +                     for (start_row = 0; start_row <
>>>>>>>>>>>>>>>>>>> (CAL_ROWS - +                          rect_height + 1);
>>>>>>>>>>>>>>>>>>> start_row++) { +                             unsigned ok
>>>>>>>>>>>>>>>>>>> = 1;
>>>>>>>>>>>>>>>>>>> +                             unsigned add_col, add_row;
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +                             /* Determine if the
>>>>>>>>>>>>>>>>>>> rectangle fits here
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> */
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                             for (add_col = 0; (add_col
>>>>>>>>>>>>>>>>>>> < rect_width)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> && ok;
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                                  add_col++) {
>>>>>>>>>>>>>>>>>>> +                                     for (add_row = 0;
>>>>>>>>>>>>>>>>>>> add_row <
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> rect_height;
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                                          add_row++) {
>>>>>>>>>>>>>>>>>>> +                                             if
>>>>>>>>>>>>>>>>>>> (!cal_results +                                         
>>>>>>>>>>>>>>>>>>>       [start_row+add_row]
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> [start_col
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                                                +
>>>>>>>>>>>>>>>>>>> add_col]) { +                                           
>>>>>>>>>>>>>>>>>>>          ok = 0; +                                      
>>>>>>>>>>>>>>>>>>>               break; +                                  
>>>>>>>>>>>>>>>>>>>           }
>>>>>>>>>>>>>>>>>>> +                                     }
>>>>>>>>>>>>>>>>>>> +                             }
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +                             /*
>>>>>>>>>>>>>>>>>>> +                              * Return 'middle' of
>>>>>>>>>>>>>>>>>>> rectangle in case
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> of
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +                              * success
>>>>>>>>>>>>>>>>>>> +                              */
>>>>>>>>>>>>>>>>>>> +                             if (ok) {
>>>>>>>>>>>>>>>>>>> +                                     if(rect_width > 1)
>>>>>>>>>>>>>>>>>>> +                                            
>>>>>>>>>>>>>>>>>>> rect_width--; +
>>>>>>>>>>>>>>>>>>> +                                     if(rect_height > 1)
>>>>>>>>>>>>>>>>>>> +                                            
>>>>>>>>>>>>>>>>>>> rect_height--; +
>>>>>>>>>>>>>>>>>>> +                                     *cal_row =
>>>>>>>>>>>>>>>>>>> start_row + +                                           
>>>>>>>>>>>>>>>>>>>     (rect_height / 2); +                                
>>>>>>>>>>>>>>>>>>>     *cal_col = start_col +
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> (rect_width / 2);
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +                                     return 0;
>>>>>>>>>>>>>>>>>>> +                             }
>>>>>>>>>>>>>>>>>>> +                     }
>>>>>>>>>>>>>>>>>>> +             }
>>>>>>>>>>>>>>>>>>> +     }
>>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>>> +     /* We could not fit any rectangle - return failure
>>>>>>>>>>>>>>>>>>> */ +     return 1;
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard
>>>>>>>>>>>>>>>>>> return codes ; -EINVAL in this case I believe.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Good suggestion, will fix in v2.
>>>>>>>>>>>>>>>>> Thanks
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Thanks. I was curious, is this really socfpga specific or
>>>>>>>>>>>>>>>> can this calibration be used on dwmmc in general -- thus on
>>>>>>>>>>>>>>>> exynos and rockchip systems -- as well? If it's generic to
>>>>>>>>>>>>>>>> dwmmc, this should be moved into the dwmmc core code. Also,
>>>>>>>>>>>>>>>> I am CCing Simon, he's been plumbing in the DWMMC recently.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I didn't see you explicitly add Simon to the thread. Doing it
>>>>>>>>>>>>> here..
>>>>>>>>>>>>
>>>>>>>>>>>> One option is to put the function in the common dw_mmc.c file
>>>>>>>>>>>> but have it be called explicitly by drivers that want it (e.g.
>>>>>>>>>>>> for now, just socfpga). The code you have written does look
>>>>>>>>>>>> generic and perhaps should be used on other platforms,
>>>>>>>>>>>>
>>>>>>>>>>>>>>> I am not sure. But definitely we can make the calibration
>>>>>>>>>>>>>>> common enough if they required the calibration too. Let wait
>>>>>>>>>>>>>>> feedback from Simon.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA,
>>>>>>>>>>>>> Exynos and Rockchip are using the drvsel and smpsel
>>>>>>>>>>>>> parameters. But I also think these parameters can
>>>>>>>>>>>>> be different for different types of SD card. Are you sure this
>>>>>>>>>>>>> function will cover those
>>>>>>>>>>>>> cases?
>>>>>>>>>>>>
>>>>>>>>>>>> Not at all, but perhaps that is something we will find out in
>>>>>>>>>>>> the future.
>>>>>>>>>>>
>>>>>>>>>>> Thanks Simon.
>>>>>>>>>>>
>>>>>>>>>>> I further checked today and noticed Exynos is setting up the
>>>>>>>>>>> clksel (sample clock and drive clock). But from exynos_dw_mmc.c,
>>>>>>>>>>> the value is coming from device tree. So I am notifying Jaehoon
>>>>>>>>>>> wonder the calibration might applicable for him.
>>>>>>>>
>>>>>>>> I think this patch should not be common code at all.
>>>>>>>> Of course, it seems that find_calibration_point function can be used
>>>>>>>> at exynos. But it's too complex and not readable.
>>>>>>>>
>>>>>>>> And smpclk and drvsel are also not common.
>>>>>>>> Depending on SoC, finding approach should be differed.
>>>>>>>> I don't know how smpclk and drvsel controlled, since i don't read
>>>>>>>> TRM of other SoC.
>>>>>>>>
>>>>>>>> Does it need to find the best clksmpl and drvsel value in
>>>>>>>> bootloader?
>>>>>>>
>>>>>>> Yah, its little complex as we try to find the best value for 2
>>>>>>> parameters together. Its also due to the nature that we rely on full
>>>>>>> complete transaction cycle to determine pass or fail (drvsel for out
>>>>>>> while clksmp for in).
>>>>>>
>>>>>> In my experiment, spmlclk value is more important than drvsel.
>>>>>> Anyway, CAL_ROWS and CAL_COLS are candiates, right?
>>>>>
>>>>> Yup, they are representing the value permutation for smplclk and drvsel.
>>>>>
>>>>>> If it can be passed by parameter from each SoC dwmmc controller, that
>>>>>> function should be located into dwmmc.c. Because drvsel and smplclk
>>>>>> bits should be difference at each SoC specific register or Generic
>>>>>> dwmmc(UHS_REG_EXT regster).
>>>>>>
>>>>>> Do you have the plan that change the more generic code than now?
>>>>>
>>>>> Actually I look back and different SoC have different register location
>>>>> for drvsel and smplclk. They are not located within dwmmc controller
>>>>> registers. As of now, they are configure within the callback function of
>>>>> clksel, I believe that should good.
>>>>
>>>> For this case, I presume the change would applicable for socfpga only
>>>> instead common dw_mmc. If everyone agreed, I shall send in new revision
>>>> of the patch.
>>>
>>> I'm not very convinced that this should be outside of the dw_mmc core.
>>
>> Would want to hear more from Jaehoon as Exynos and SOCFPGA are the one
>> setting up these values.
> 
> Since this approach is not based on dwmmc TRM, it's based on SOCFPGA SoC,
> i think that it doesn't need to include into dwmmc core.
> If need to located into dwmmc core, this code needs to modify more.
> 
> As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not core feature.
> Other SoC can't be used them. we don't know.
> 
> 

Plus the way that this function is implemented, it is very specific to
SoCFGA, as the tables and rows are representing 45 degree increments for
the drvsel and smplsel value. Other platforms can have either more or
less granularity in the drvsel and smplsel values.

Dinh

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-01 14:53                                     ` Dinh Nguyen
@ 2015-09-02 10:32                                       ` Marek Vasut
  2015-09-03  0:27                                         ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-09-02 10:32 UTC (permalink / raw)
  To: u-boot

On Tuesday, September 01, 2015 at 04:53:44 PM, Dinh Nguyen wrote:
> On 09/01/2015 05:12 AM, Jaehoon Chung wrote:
> > On 09/01/2015 06:10 PM, Chin Liang See wrote:
> >> On Tue, 2015-09-01 at 11:01 +0200, marex at denx.de wrote:
> >>> On Tuesday, September 01, 2015 at 10:54:06 AM, Chin Liang See wrote:
> >>>> On Wed, 2015-08-26 at 01:54 -0500, Chin Liang See wrote:
> >>>>> On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
> >>>>>> On 08/26/2015 02:47 PM, Chin Liang See wrote:
> >>>>>>> On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
> >>>>>>>> Hi,
> >>>>>>>> 
> >>>>>>>> On 08/25/2015 12:08 PM, Chin Liang See wrote:
> >>>>>>>>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> >>>>>>>>>> Hi,
> >>>>>>>>>> 
> >>>>>>>>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> >>>>>>>>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> >>>>>>>>>>>> Hi,
> >>>>>>>>>>>> 
> >>>>>>>>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com>
> >>> 
> >>> wrote:
> >>>>>>>>>>>>> +CC: Simon Glass
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de>
> >>> 
> >>> wrote:
> >>>>>>>>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See
> >>> 
> >>> wrote:
> >>>>>>>>>>>>>>> Hi,
> >>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> >>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang
> >>>>>>>>>>>>>>>> See
> >>> 
> >>> wrote:
> >>>>>>>>>>>>>>>>> Hi,
> >>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>> Hi again,
> >>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> >>>>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang
> >>>>>>>>>>>>>>>>>> See
> >>> 
> >>> wrote:
> >>>>>>>>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting
> >>>>>>>>>>>>>>>>>>> for drvsel and smpsel. It will be triggered whenever
> >>>>>>>>>>>>>>>>>>> there is a change of card frequency and bus width. This
> >>>>>>>>>>>>>>>>>>> is to ensure reliable transmission between the
> >>>>>>>>>>>>>>>>>>> controller and the card.
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> >>>>>>>>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> I think there's something wrong with your git scripts, I did
> >>>>>>>>>>>>> not get this email.
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> >>>>>>>>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> >>>>>>>>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> >>>>>>>>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> >>>>>>>>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> >>>>>>>>>>>>>>>>>>> ---
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files
> >>>>>>>>>>>>>>>>>>> changed, 180 insertions(+), 7 deletions(-)
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c
> >>>>>>>>>>>>>>>>>>> 100644 --- a/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> >>>>>>>>>>>>>>>>>>> @@ -11,25 +11,140 @@
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
> >>>>>>>>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
> >>>>>>>>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +#include "mmc_private.h"
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>  static const struct socfpga_clock_manager
> >>>>>>>>>>>>>>>>>>>  *clock_manager_base =
> >>>>>>>>>>>>>>>>>>>  
> >>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> >>>>>>>>>>>>>>>>>>>  
> >>>>>>>>>>>>>>>>>>>  static const struct socfpga_system_manager
> >>>>>>>>>>>>>>>>>>>  *system_manager_base =
> >>>>>>>>>>>>>>>>>>>  
> >>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host
> >>>>>>>>>>>>>>>>>>> *host) +#define CAL_ROWS     7
> >>>>>>>>>>>>>>>>>>> +#define CAL_COLS     8
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +/*
> >>>>>>>>>>>>>>>>>>> + * This function determines the largest rectangle
> >>>>>>>>>>>>>>>>>>> filled with 1's and returns + * the middle. This
> >>>>>>>>>>>>>>>>>>> functon can be optimized, for example using the
> >>>>>>>>>>>>>>>>>>> algorithm + * from
> >>>>>>>>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-
> >>>>>>>>>>>>>>>>>>> pro blem/18441 0529 + * It currently takes less than
> >>>>>>>>>>>>>>>>>>> 1ms, while creating the input data takes ~5ms + * so
> >>>>>>>>>>>>>>>>>>> there is not a real need to optimize it. + */
> >>>>>>>>>>>>>>>>>>> +int find_calibration_point(unsigned char
> >>>>>>>>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum,
> >>>>>>>>>>>>>>>>>>> unsigned int * cal_row, unsigned int * cal_col)
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>  {
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> -     unsigned int drvsel;
> >>>>>>>>>>>>>>>>>>> -     unsigned int smplsel;
> >>>>>>>>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
> >>>>>>>>>>>>>>>>>>> +     typedef struct
> >>>>>>>>>>>>>>>>>>> +     {
> >>>>>>>>>>>>>>>>>>> +             unsigned char height;
> >>>>>>>>>>>>>>>>>>> +             unsigned char width;
> >>>>>>>>>>>>>>>>>>> +             unsigned short area;
> >>>>>>>>>>>>>>>>>>> +     } rect_cand_t;
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +     /* Array with the rectangle candidates */
> >>>>>>>>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> >>>>>>>>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
> >>>>>>>>>>>>>>>>>>> +     unsigned char height, width, k;
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +     /* No solution if all combinations fail */
> >>>>>>>>>>>>>>>>>>> +     if(sum == 0)
> >>>>>>>>>>>>>>>>>>> +             return 1;
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
> >>>>>>>>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> >>>>>>>>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> >>>>>>>>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> >>>>>>>>>>>>>>>>>>> +             return 0;
> >>>>>>>>>>>>>>>>>>> +     }
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +     /*
> >>>>>>>>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in
> >>>>>>>>>>>>>>>>>>> descending
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> area
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +      * order
> >>>>>>>>>>>>>>>>>>> +      */
> >>>>>>>>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> >>>>>>>>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ;
> >>>>>>>>>>>>>>>>>>> width--){ +                     /* Add a new rectangle
> >>>>>>>>>>>>>>>>>>> candidate */ +
> >>>>>>>>>>>>>>>>>>> rect_cands[cr_rect_cand].height = height; +
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>        rect_cands[cr_rect_cand].width = width; +
> >>>>>>>>>>>>>>>>>>>        
> >>>>>>>>>>>>>>>>>>>             rect_cands[cr_rect_cand].area = height *
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> width; +                     cr_rect_cand++;
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +                     /* First candidate it always in
> >>>>>>>>>>>>>>>>>>> the right
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> position */
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
> >>>>>>>>>>>>>>>>>>> +                             continue;
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +                     /*
> >>>>>>>>>>>>>>>>>>> +                      * Put the candidate in right
> >>>>>>>>>>>>>>>>>>> location to
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> maintain
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                      * descending order
> >>>>>>>>>>>>>>>>>>> +                      */
> >>>>>>>>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1;
> >>>>>>>>>>>>>>>>>>> k--){ +
> >>>>>>>>>>>>>>>>>>> if(rect_cands[k-1].area <
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> rect_cands[k].area){
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                                     rect_cand_t tmp =
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> rect_cands[k-1];
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                                     rect_cands[k-1] =
> >>>>>>>>>>>>>>>>>>> rect_cands[k]; +
> >>>>>>>>>>>>>>>>>>> rect_cands[k] = tmp; +                             }
> >>>>>>>>>>>>>>>>>>> else
> >>>>>>>>>>>>>>>>>>> +                                     break;
> >>>>>>>>>>>>>>>>>>> +                     }
> >>>>>>>>>>>>>>>>>>> +             }
> >>>>>>>>>>>>>>>>>>> +     }
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in
> >>>>>>>>>>>>>>>>>>> descending area order */ +  for(k = 0; k < CAL_ROWS *
> >>>>>>>>>>>>>>>>>>> CAL_COLS; k++) { +             unsigned char start_row,
> >>>>>>>>>>>>>>>>>>> start_col; +             unsigned rect_width =
> >>>>>>>>>>>>>>>>>>> rect_cands[k].width; +             unsigned rect_height
> >>>>>>>>>>>>>>>>>>> = rect_cands[k].height; +
> >>>>>>>>>>>>>>>>>>> +             /* Find the row and column where the
> >>>>>>>>>>>>>>>>>>> candidate fits */ +             for (start_col = 0;
> >>>>>>>>>>>>>>>>>>> start_col < (CAL_COLS - rect_width +
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> 1);
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                  start_col++) {
> >>>>>>>>>>>>>>>>>>> +                     for (start_row = 0; start_row <
> >>>>>>>>>>>>>>>>>>> (CAL_ROWS - +                          rect_height +
> >>>>>>>>>>>>>>>>>>> 1); start_row++) { +                            
> >>>>>>>>>>>>>>>>>>> unsigned ok = 1;
> >>>>>>>>>>>>>>>>>>> +                             unsigned add_col,
> >>>>>>>>>>>>>>>>>>> add_row; +
> >>>>>>>>>>>>>>>>>>> +                             /* Determine if the
> >>>>>>>>>>>>>>>>>>> rectangle fits here
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> */
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                             for (add_col = 0;
> >>>>>>>>>>>>>>>>>>> (add_col < rect_width)
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> && ok;
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                                  add_col++) {
> >>>>>>>>>>>>>>>>>>> +                                     for (add_row = 0;
> >>>>>>>>>>>>>>>>>>> add_row <
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> rect_height;
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                                          add_row++) {
> >>>>>>>>>>>>>>>>>>> +                                             if
> >>>>>>>>>>>>>>>>>>> (!cal_results +
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>       [start_row+add_row]
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> [start_col
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                                                +
> >>>>>>>>>>>>>>>>>>> add_col]) { +
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>          ok = 0; +
> >>>>>>>>>>>>>>>>>>>          
> >>>>>>>>>>>>>>>>>>>               break; +
> >>>>>>>>>>>>>>>>>>>           
> >>>>>>>>>>>>>>>>>>>           }
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                                     }
> >>>>>>>>>>>>>>>>>>> +                             }
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +                             /*
> >>>>>>>>>>>>>>>>>>> +                              * Return 'middle' of
> >>>>>>>>>>>>>>>>>>> rectangle in case
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> of
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +                              * success
> >>>>>>>>>>>>>>>>>>> +                              */
> >>>>>>>>>>>>>>>>>>> +                             if (ok) {
> >>>>>>>>>>>>>>>>>>> +                                     if(rect_width >
> >>>>>>>>>>>>>>>>>>> 1) +
> >>>>>>>>>>>>>>>>>>> rect_width--; +
> >>>>>>>>>>>>>>>>>>> +                                     if(rect_height >
> >>>>>>>>>>>>>>>>>>> 1) +
> >>>>>>>>>>>>>>>>>>> rect_height--; +
> >>>>>>>>>>>>>>>>>>> +                                     *cal_row =
> >>>>>>>>>>>>>>>>>>> start_row + +
> >>>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>>     (rect_height / 2); +
> >>>>>>>>>>>>>>>>>>>     *cal_col = start_col +
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> (rect_width / 2);
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +                                     return 0;
> >>>>>>>>>>>>>>>>>>> +                             }
> >>>>>>>>>>>>>>>>>>> +                     }
> >>>>>>>>>>>>>>>>>>> +             }
> >>>>>>>>>>>>>>>>>>> +     }
> >>>>>>>>>>>>>>>>>>> +
> >>>>>>>>>>>>>>>>>>> +     /* We could not fit any rectangle - return
> >>>>>>>>>>>>>>>>>>> failure */ +     return 1;
> >>>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard
> >>>>>>>>>>>>>>>>>> return codes ; -EINVAL in this case I believe.
> >>>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>>> Good suggestion, will fix in v2.
> >>>>>>>>>>>>>>>>> Thanks
> >>>>>>>>>>>>>>>> 
> >>>>>>>>>>>>>>>> Thanks. I was curious, is this really socfpga specific or
> >>>>>>>>>>>>>>>> can this calibration be used on dwmmc in general -- thus
> >>>>>>>>>>>>>>>> on exynos and rockchip systems -- as well? If it's
> >>>>>>>>>>>>>>>> generic to dwmmc, this should be moved into the dwmmc
> >>>>>>>>>>>>>>>> core code. Also, I am CCing Simon, he's been plumbing in
> >>>>>>>>>>>>>>>> the DWMMC recently.
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> I didn't see you explicitly add Simon to the thread. Doing it
> >>>>>>>>>>>>> here..
> >>>>>>>>>>>> 
> >>>>>>>>>>>> One option is to put the function in the common dw_mmc.c file
> >>>>>>>>>>>> but have it be called explicitly by drivers that want it (e.g.
> >>>>>>>>>>>> for now, just socfpga). The code you have written does look
> >>>>>>>>>>>> generic and perhaps should be used on other platforms,
> >>>>>>>>>>>> 
> >>>>>>>>>>>>>>> I am not sure. But definitely we can make the calibration
> >>>>>>>>>>>>>>> common enough if they required the calibration too. Let
> >>>>>>>>>>>>>>> wait feedback from Simon.
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA,
> >>>>>>>>>>>>> Exynos and Rockchip are using the drvsel and smpsel
> >>>>>>>>>>>>> parameters. But I also think these parameters can
> >>>>>>>>>>>>> be different for different types of SD card. Are you sure
> >>>>>>>>>>>>> this function will cover those
> >>>>>>>>>>>>> cases?
> >>>>>>>>>>>> 
> >>>>>>>>>>>> Not at all, but perhaps that is something we will find out in
> >>>>>>>>>>>> the future.
> >>>>>>>>>>> 
> >>>>>>>>>>> Thanks Simon.
> >>>>>>>>>>> 
> >>>>>>>>>>> I further checked today and noticed Exynos is setting up the
> >>>>>>>>>>> clksel (sample clock and drive clock). But from
> >>>>>>>>>>> exynos_dw_mmc.c, the value is coming from device tree. So I am
> >>>>>>>>>>> notifying Jaehoon wonder the calibration might applicable for
> >>>>>>>>>>> him.
> >>>>>>>> 
> >>>>>>>> I think this patch should not be common code at all.
> >>>>>>>> Of course, it seems that find_calibration_point function can be
> >>>>>>>> used at exynos. But it's too complex and not readable.
> >>>>>>>> 
> >>>>>>>> And smpclk and drvsel are also not common.
> >>>>>>>> Depending on SoC, finding approach should be differed.
> >>>>>>>> I don't know how smpclk and drvsel controlled, since i don't read
> >>>>>>>> TRM of other SoC.
> >>>>>>>> 
> >>>>>>>> Does it need to find the best clksmpl and drvsel value in
> >>>>>>>> bootloader?
> >>>>>>> 
> >>>>>>> Yah, its little complex as we try to find the best value for 2
> >>>>>>> parameters together. Its also due to the nature that we rely on
> >>>>>>> full complete transaction cycle to determine pass or fail (drvsel
> >>>>>>> for out while clksmp for in).
> >>>>>> 
> >>>>>> In my experiment, spmlclk value is more important than drvsel.
> >>>>>> Anyway, CAL_ROWS and CAL_COLS are candiates, right?
> >>>>> 
> >>>>> Yup, they are representing the value permutation for smplclk and
> >>>>> drvsel.
> >>>>> 
> >>>>>> If it can be passed by parameter from each SoC dwmmc controller,
> >>>>>> that function should be located into dwmmc.c. Because drvsel and
> >>>>>> smplclk bits should be difference at each SoC specific register or
> >>>>>> Generic dwmmc(UHS_REG_EXT regster).
> >>>>>> 
> >>>>>> Do you have the plan that change the more generic code than now?
> >>>>> 
> >>>>> Actually I look back and different SoC have different register
> >>>>> location for drvsel and smplclk. They are not located within dwmmc
> >>>>> controller registers. As of now, they are configure within the
> >>>>> callback function of clksel, I believe that should good.
> >>>> 
> >>>> For this case, I presume the change would applicable for socfpga only
> >>>> instead common dw_mmc. If everyone agreed, I shall send in new
> >>>> revision of the patch.
> >>> 
> >>> I'm not very convinced that this should be outside of the dw_mmc core.
> >> 
> >> Would want to hear more from Jaehoon as Exynos and SOCFPGA are the one
> >> setting up these values.
> > 
> > Since this approach is not based on dwmmc TRM, it's based on SOCFPGA SoC,
> > i think that it doesn't need to include into dwmmc core.
> > If need to located into dwmmc core, this code needs to modify more.
> > 
> > As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not core
> > feature. Other SoC can't be used them. we don't know.
> 
> Plus the way that this function is implemented, it is very specific to
> SoCFGA, as the tables and rows are representing 45 degree increments for
> the drvsel and smplsel value. Other platforms can have either more or
> less granularity in the drvsel and smplsel values.

How is this SMPLSEL and DRVSEL implemented on Exynos ?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-02 10:32                                       ` Marek Vasut
@ 2015-09-03  0:27                                         ` Chin Liang See
  2015-09-03  5:30                                           ` Jaehoon Chung
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-09-03  0:27 UTC (permalink / raw)
  To: u-boot

On Wed, 2015-09-02 at 12:32 +0200, marex at denx.de wrote:
> On Tuesday, September 01, 2015 at 04:53:44 PM, Dinh Nguyen wrote:
> > On 09/01/2015 05:12 AM, Jaehoon Chung wrote:
> > > On 09/01/2015 06:10 PM, Chin Liang See wrote:
> > >> On Tue, 2015-09-01 at 11:01 +0200, marex at denx.de wrote:
> > >>> On Tuesday, September 01, 2015 at 10:54:06 AM, Chin Liang See wrote:
> > >>>> On Wed, 2015-08-26 at 01:54 -0500, Chin Liang See wrote:
> > >>>>> On Wed, 2015-08-26 at 15:14 +0900, Jaehoon Chung wrote:
> > >>>>>> On 08/26/2015 02:47 PM, Chin Liang See wrote:
> > >>>>>>> On Wed, 2015-08-26 at 14:29 +0900, Jaehoon Chung wrote:
> > >>>>>>>> Hi,
> > >>>>>>>> 
> > >>>>>>>> On 08/25/2015 12:08 PM, Chin Liang See wrote:
> > >>>>>>>>> On Tue, 2015-08-25 at 11:36 +0900, Jaehoon Chung wrote:
> > >>>>>>>>>> Hi,
> > >>>>>>>>>> 
> > >>>>>>>>>> On 08/25/2015 12:04 AM, Chin Liang See wrote:
> > >>>>>>>>>>> On Fri, 2015-08-21 at 14:52 -0600, Simon Glass wrote:
> > >>>>>>>>>>>> Hi,
> > >>>>>>>>>>>> 
> > >>>>>>>>>>>> On 20 August 2015 at 15:55, Dinh Nguyen <dinh.linux@gmail.com>
> > >>> 
> > >>> wrote:
> > >>>>>>>>>>>>> +CC: Simon Glass
> > >>>>>>>>>>>>> 
> > >>>>>>>>>>>>> On Thu, Aug 20, 2015 at 12:32 AM, Marek Vasut <marex@denx.de>
> > >>> 
> > >>> wrote:
> > >>>>>>>>>>>>>> On Thursday, August 20, 2015 at 07:28:02 AM, Chin Liang See
> > >>> 
> > >>> wrote:
> > >>>>>>>>>>>>>>> Hi,
> > >>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>> On Wed, 2015-08-19 at 14:36 +0000, marex at denx.de wrote:
> > >>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 10:21:17 AM, Chin Liang
> > >>>>>>>>>>>>>>>> See
> > >>> 
> > >>> wrote:
> > >>>>>>>>>>>>>>>>> Hi,
> > >>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>> Hi again,
> > >>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>> On Wed, 2015-08-19 at 02:41 +0000, marex at denx.de wrote:
> > >>>>>>>>>>>>>>>>>> On Wednesday, August 19, 2015 at 07:54:50 AM, Chin Liang
> > >>>>>>>>>>>>>>>>>> See
> > >>> 
> > >>> wrote:
> > >>>>>>>>>>>>>>>>>>> Enable SDMMC calibration to determine the best setting
> > >>>>>>>>>>>>>>>>>>> for drvsel and smpsel. It will be triggered whenever
> > >>>>>>>>>>>>>>>>>>> there is a change of card frequency and bus width. This
> > >>>>>>>>>>>>>>>>>>> is to ensure reliable transmission between the
> > >>>>>>>>>>>>>>>>>>> controller and the card.
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> Signed-off-by: Chin Liang See <clsee@altera.com>
> > >>>>>>>>>>>>>>>>>>> Cc: Dinh Nguyen <dinguyen@opensource.altera.com>
> > >>>>>>>>>>>>> 
> > >>>>>>>>>>>>> I think there's something wrong with your git scripts, I did
> > >>>>>>>>>>>>> not get this email.
> > >>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> Cc: Pavel Machek <pavel@denx.de>
> > >>>>>>>>>>>>>>>>>>> Cc: Marek Vasut <marex@denx.de>
> > >>>>>>>>>>>>>>>>>>> Cc: Wolfgang Denk <wd@denx.de>
> > >>>>>>>>>>>>>>>>>>> Cc: Stefan Roese <sr@denx.de>
> > >>>>>>>>>>>>>>>>>>> Cc: Tom Rini <trini@konsulko.com>
> > >>>>>>>>>>>>>>>>>>> ---
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>  drivers/mmc/socfpga_dw_mmc.c |  187
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++-- 1 files
> > >>>>>>>>>>>>>>>>>>> changed, 180 insertions(+), 7 deletions(-)
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> diff --git a/drivers/mmc/socfpga_dw_mmc.c
> > >>>>>>>>>>>>>>>>>>> b/drivers/mmc/socfpga_dw_mmc.c index eb69aed..15e537c
> > >>>>>>>>>>>>>>>>>>> 100644 --- a/drivers/mmc/socfpga_dw_mmc.c
> > >>>>>>>>>>>>>>>>>>> +++ b/drivers/mmc/socfpga_dw_mmc.c
> > >>>>>>>>>>>>>>>>>>> @@ -11,25 +11,140 @@
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>  #include <asm/arch/dwmmc.h>
> > >>>>>>>>>>>>>>>>>>>  #include <asm/arch/clock_manager.h>
> > >>>>>>>>>>>>>>>>>>>  #include <asm/arch/system_manager.h>
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +#include "mmc_private.h"
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>  static const struct socfpga_clock_manager
> > >>>>>>>>>>>>>>>>>>>  *clock_manager_base =
> > >>>>>>>>>>>>>>>>>>>  
> > >>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_CLKMGR_ADDRESS;
> > >>>>>>>>>>>>>>>>>>>  
> > >>>>>>>>>>>>>>>>>>>  static const struct socfpga_system_manager
> > >>>>>>>>>>>>>>>>>>>  *system_manager_base =
> > >>>>>>>>>>>>>>>>>>>  
> > >>>>>>>>>>>>>>>>>>>               (void *)SOCFPGA_SYSMGR_ADDRESS;
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> -static void socfpga_dwmci_clksel(struct dwmci_host
> > >>>>>>>>>>>>>>>>>>> *host) +#define CAL_ROWS     7
> > >>>>>>>>>>>>>>>>>>> +#define CAL_COLS     8
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +/*
> > >>>>>>>>>>>>>>>>>>> + * This function determines the largest rectangle
> > >>>>>>>>>>>>>>>>>>> filled with 1's and returns + * the middle. This
> > >>>>>>>>>>>>>>>>>>> functon can be optimized, for example using the
> > >>>>>>>>>>>>>>>>>>> algorithm + * from
> > >>>>>>>>>>>>>>>>>>> http://www.drdobbs.com/database/the-maximal-rectangle-
> > >>>>>>>>>>>>>>>>>>> pro blem/18441 0529 + * It currently takes less than
> > >>>>>>>>>>>>>>>>>>> 1ms, while creating the input data takes ~5ms + * so
> > >>>>>>>>>>>>>>>>>>> there is not a real need to optimize it. + */
> > >>>>>>>>>>>>>>>>>>> +int find_calibration_point(unsigned char
> > >>>>>>>>>>>>>>>>>>> cal_results[CAL_ROWS][CAL_COLS], +unsigned int sum,
> > >>>>>>>>>>>>>>>>>>> unsigned int * cal_row, unsigned int * cal_col)
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>  {
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> -     unsigned int drvsel;
> > >>>>>>>>>>>>>>>>>>> -     unsigned int smplsel;
> > >>>>>>>>>>>>>>>>>>> +     /* Structure containing a rectangle candidate */
> > >>>>>>>>>>>>>>>>>>> +     typedef struct
> > >>>>>>>>>>>>>>>>>>> +     {
> > >>>>>>>>>>>>>>>>>>> +             unsigned char height;
> > >>>>>>>>>>>>>>>>>>> +             unsigned char width;
> > >>>>>>>>>>>>>>>>>>> +             unsigned short area;
> > >>>>>>>>>>>>>>>>>>> +     } rect_cand_t;
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +     /* Array with the rectangle candidates */
> > >>>>>>>>>>>>>>>>>>> +     rect_cand_t rect_cands[CAL_ROWS * CAL_COLS];
> > >>>>>>>>>>>>>>>>>>> +     unsigned char cr_rect_cand = 0;
> > >>>>>>>>>>>>>>>>>>> +     unsigned char height, width, k;
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +     /* No solution if all combinations fail */
> > >>>>>>>>>>>>>>>>>>> +     if(sum == 0)
> > >>>>>>>>>>>>>>>>>>> +             return 1;
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +     /* Simple solution if all combinations pass */
> > >>>>>>>>>>>>>>>>>>> +     if(sum == (CAL_ROWS * CAL_COLS)) {
> > >>>>>>>>>>>>>>>>>>> +             *cal_row = (CAL_ROWS - 1) / 2;
> > >>>>>>>>>>>>>>>>>>> +             *cal_col = (CAL_COLS - 1) / 2;
> > >>>>>>>>>>>>>>>>>>> +             return 0;
> > >>>>>>>>>>>>>>>>>>> +     }
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +     /*
> > >>>>>>>>>>>>>>>>>>> +      * Create list of all possible sub-rectangles, in
> > >>>>>>>>>>>>>>>>>>> descending
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> area
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +      * order
> > >>>>>>>>>>>>>>>>>>> +      */
> > >>>>>>>>>>>>>>>>>>> +     for(height = CAL_ROWS; height >= 1; height--) {
> > >>>>>>>>>>>>>>>>>>> +             for(width = CAL_COLS; width >= 1 ;
> > >>>>>>>>>>>>>>>>>>> width--){ +                     /* Add a new rectangle
> > >>>>>>>>>>>>>>>>>>> candidate */ +
> > >>>>>>>>>>>>>>>>>>> rect_cands[cr_rect_cand].height = height; +
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>        rect_cands[cr_rect_cand].width = width; +
> > >>>>>>>>>>>>>>>>>>>        
> > >>>>>>>>>>>>>>>>>>>             rect_cands[cr_rect_cand].area = height *
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> width; +                     cr_rect_cand++;
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +                     /* First candidate it always in
> > >>>>>>>>>>>>>>>>>>> the right
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> position */
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                     if(cr_rect_cand == 1)
> > >>>>>>>>>>>>>>>>>>> +                             continue;
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +                     /*
> > >>>>>>>>>>>>>>>>>>> +                      * Put the candidate in right
> > >>>>>>>>>>>>>>>>>>> location to
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> maintain
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                      * descending order
> > >>>>>>>>>>>>>>>>>>> +                      */
> > >>>>>>>>>>>>>>>>>>> +                     for(k = cr_rect_cand - 1; k > 1;
> > >>>>>>>>>>>>>>>>>>> k--){ +
> > >>>>>>>>>>>>>>>>>>> if(rect_cands[k-1].area <
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> rect_cands[k].area){
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                                     rect_cand_t tmp =
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> rect_cands[k-1];
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                                     rect_cands[k-1] =
> > >>>>>>>>>>>>>>>>>>> rect_cands[k]; +
> > >>>>>>>>>>>>>>>>>>> rect_cands[k] = tmp; +                             }
> > >>>>>>>>>>>>>>>>>>> else
> > >>>>>>>>>>>>>>>>>>> +                                     break;
> > >>>>>>>>>>>>>>>>>>> +                     }
> > >>>>>>>>>>>>>>>>>>> +             }
> > >>>>>>>>>>>>>>>>>>> +     }
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +     /* Try to fit the rectangle candidates, in
> > >>>>>>>>>>>>>>>>>>> descending area order */ +  for(k = 0; k < CAL_ROWS *
> > >>>>>>>>>>>>>>>>>>> CAL_COLS; k++) { +             unsigned char start_row,
> > >>>>>>>>>>>>>>>>>>> start_col; +             unsigned rect_width =
> > >>>>>>>>>>>>>>>>>>> rect_cands[k].width; +             unsigned rect_height
> > >>>>>>>>>>>>>>>>>>> = rect_cands[k].height; +
> > >>>>>>>>>>>>>>>>>>> +             /* Find the row and column where the
> > >>>>>>>>>>>>>>>>>>> candidate fits */ +             for (start_col = 0;
> > >>>>>>>>>>>>>>>>>>> start_col < (CAL_COLS - rect_width +
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> 1);
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                  start_col++) {
> > >>>>>>>>>>>>>>>>>>> +                     for (start_row = 0; start_row <
> > >>>>>>>>>>>>>>>>>>> (CAL_ROWS - +                          rect_height +
> > >>>>>>>>>>>>>>>>>>> 1); start_row++) { +                            
> > >>>>>>>>>>>>>>>>>>> unsigned ok = 1;
> > >>>>>>>>>>>>>>>>>>> +                             unsigned add_col,
> > >>>>>>>>>>>>>>>>>>> add_row; +
> > >>>>>>>>>>>>>>>>>>> +                             /* Determine if the
> > >>>>>>>>>>>>>>>>>>> rectangle fits here
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> */
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                             for (add_col = 0;
> > >>>>>>>>>>>>>>>>>>> (add_col < rect_width)
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> && ok;
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                                  add_col++) {
> > >>>>>>>>>>>>>>>>>>> +                                     for (add_row = 0;
> > >>>>>>>>>>>>>>>>>>> add_row <
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> rect_height;
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                                          add_row++) {
> > >>>>>>>>>>>>>>>>>>> +                                             if
> > >>>>>>>>>>>>>>>>>>> (!cal_results +
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>       [start_row+add_row]
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> [start_col
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                                                +
> > >>>>>>>>>>>>>>>>>>> add_col]) { +
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>          ok = 0; +
> > >>>>>>>>>>>>>>>>>>>          
> > >>>>>>>>>>>>>>>>>>>               break; +
> > >>>>>>>>>>>>>>>>>>>           
> > >>>>>>>>>>>>>>>>>>>           }
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                                     }
> > >>>>>>>>>>>>>>>>>>> +                             }
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +                             /*
> > >>>>>>>>>>>>>>>>>>> +                              * Return 'middle' of
> > >>>>>>>>>>>>>>>>>>> rectangle in case
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> of
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +                              * success
> > >>>>>>>>>>>>>>>>>>> +                              */
> > >>>>>>>>>>>>>>>>>>> +                             if (ok) {
> > >>>>>>>>>>>>>>>>>>> +                                     if(rect_width >
> > >>>>>>>>>>>>>>>>>>> 1) +
> > >>>>>>>>>>>>>>>>>>> rect_width--; +
> > >>>>>>>>>>>>>>>>>>> +                                     if(rect_height >
> > >>>>>>>>>>>>>>>>>>> 1) +
> > >>>>>>>>>>>>>>>>>>> rect_height--; +
> > >>>>>>>>>>>>>>>>>>> +                                     *cal_row =
> > >>>>>>>>>>>>>>>>>>> start_row + +
> > >>>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>>     (rect_height / 2); +
> > >>>>>>>>>>>>>>>>>>>     *cal_col = start_col +
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>> (rect_width / 2);
> > >>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +                                     return 0;
> > >>>>>>>>>>>>>>>>>>> +                             }
> > >>>>>>>>>>>>>>>>>>> +                     }
> > >>>>>>>>>>>>>>>>>>> +             }
> > >>>>>>>>>>>>>>>>>>> +     }
> > >>>>>>>>>>>>>>>>>>> +
> > >>>>>>>>>>>>>>>>>>> +     /* We could not fit any rectangle - return
> > >>>>>>>>>>>>>>>>>>> failure */ +     return 1;
> > >>>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>>> Oh btw. please make sure to use errno.h and standard
> > >>>>>>>>>>>>>>>>>> return codes ; -EINVAL in this case I believe.
> > >>>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>>> Good suggestion, will fix in v2.
> > >>>>>>>>>>>>>>>>> Thanks
> > >>>>>>>>>>>>>>>> 
> > >>>>>>>>>>>>>>>> Thanks. I was curious, is this really socfpga specific or
> > >>>>>>>>>>>>>>>> can this calibration be used on dwmmc in general -- thus
> > >>>>>>>>>>>>>>>> on exynos and rockchip systems -- as well? If it's
> > >>>>>>>>>>>>>>>> generic to dwmmc, this should be moved into the dwmmc
> > >>>>>>>>>>>>>>>> core code. Also, I am CCing Simon, he's been plumbing in
> > >>>>>>>>>>>>>>>> the DWMMC recently.
> > >>>>>>>>>>>>> 
> > >>>>>>>>>>>>> I didn't see you explicitly add Simon to the thread. Doing it
> > >>>>>>>>>>>>> here..
> > >>>>>>>>>>>> 
> > >>>>>>>>>>>> One option is to put the function in the common dw_mmc.c file
> > >>>>>>>>>>>> but have it be called explicitly by drivers that want it (e.g.
> > >>>>>>>>>>>> for now, just socfpga). The code you have written does look
> > >>>>>>>>>>>> generic and perhaps should be used on other platforms,
> > >>>>>>>>>>>> 
> > >>>>>>>>>>>>>>> I am not sure. But definitely we can make the calibration
> > >>>>>>>>>>>>>>> common enough if they required the calibration too. Let
> > >>>>>>>>>>>>>>> wait feedback from Simon.
> > >>>>>>>>>>>>> 
> > >>>>>>>>>>>>> I know that the linux driver for the DW MMC  for SoCFGPA,
> > >>>>>>>>>>>>> Exynos and Rockchip are using the drvsel and smpsel
> > >>>>>>>>>>>>> parameters. But I also think these parameters can
> > >>>>>>>>>>>>> be different for different types of SD card. Are you sure
> > >>>>>>>>>>>>> this function will cover those
> > >>>>>>>>>>>>> cases?
> > >>>>>>>>>>>> 
> > >>>>>>>>>>>> Not at all, but perhaps that is something we will find out in
> > >>>>>>>>>>>> the future.
> > >>>>>>>>>>> 
> > >>>>>>>>>>> Thanks Simon.
> > >>>>>>>>>>> 
> > >>>>>>>>>>> I further checked today and noticed Exynos is setting up the
> > >>>>>>>>>>> clksel (sample clock and drive clock). But from
> > >>>>>>>>>>> exynos_dw_mmc.c, the value is coming from device tree. So I am
> > >>>>>>>>>>> notifying Jaehoon wonder the calibration might applicable for
> > >>>>>>>>>>> him.
> > >>>>>>>> 
> > >>>>>>>> I think this patch should not be common code at all.
> > >>>>>>>> Of course, it seems that find_calibration_point function can be
> > >>>>>>>> used at exynos. But it's too complex and not readable.
> > >>>>>>>> 
> > >>>>>>>> And smpclk and drvsel are also not common.
> > >>>>>>>> Depending on SoC, finding approach should be differed.
> > >>>>>>>> I don't know how smpclk and drvsel controlled, since i don't read
> > >>>>>>>> TRM of other SoC.
> > >>>>>>>> 
> > >>>>>>>> Does it need to find the best clksmpl and drvsel value in
> > >>>>>>>> bootloader?
> > >>>>>>> 
> > >>>>>>> Yah, its little complex as we try to find the best value for 2
> > >>>>>>> parameters together. Its also due to the nature that we rely on
> > >>>>>>> full complete transaction cycle to determine pass or fail (drvsel
> > >>>>>>> for out while clksmp for in).
> > >>>>>> 
> > >>>>>> In my experiment, spmlclk value is more important than drvsel.
> > >>>>>> Anyway, CAL_ROWS and CAL_COLS are candiates, right?
> > >>>>> 
> > >>>>> Yup, they are representing the value permutation for smplclk and
> > >>>>> drvsel.
> > >>>>> 
> > >>>>>> If it can be passed by parameter from each SoC dwmmc controller,
> > >>>>>> that function should be located into dwmmc.c. Because drvsel and
> > >>>>>> smplclk bits should be difference at each SoC specific register or
> > >>>>>> Generic dwmmc(UHS_REG_EXT regster).
> > >>>>>> 
> > >>>>>> Do you have the plan that change the more generic code than now?
> > >>>>> 
> > >>>>> Actually I look back and different SoC have different register
> > >>>>> location for drvsel and smplclk. They are not located within dwmmc
> > >>>>> controller registers. As of now, they are configure within the
> > >>>>> callback function of clksel, I believe that should good.
> > >>>> 
> > >>>> For this case, I presume the change would applicable for socfpga only
> > >>>> instead common dw_mmc. If everyone agreed, I shall send in new
> > >>>> revision of the patch.
> > >>> 
> > >>> I'm not very convinced that this should be outside of the dw_mmc core.
> > >> 
> > >> Would want to hear more from Jaehoon as Exynos and SOCFPGA are the one
> > >> setting up these values.
> > > 
> > > Since this approach is not based on dwmmc TRM, it's based on SOCFPGA SoC,
> > > i think that it doesn't need to include into dwmmc core.
> > > If need to located into dwmmc core, this code needs to modify more.
> > > 
> > > As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not core
> > > feature. Other SoC can't be used them. we don't know.
> > 
> > Plus the way that this function is implemented, it is very specific to
> > SoCFGA, as the tables and rows are representing 45 degree increments for
> > the drvsel and smplsel value. Other platforms can have either more or
> > less granularity in the drvsel and smplsel values.
> 
> How is this SMPLSEL and DRVSEL implemented on Exynos ?

The value comes from device tree.

Thanks
Chin Liang

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-03  0:27                                         ` Chin Liang See
@ 2015-09-03  5:30                                           ` Jaehoon Chung
  2015-09-03  9:37                                             ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Jaehoon Chung @ 2015-09-03  5:30 UTC (permalink / raw)
  To: u-boot

Hi, 

On 09/03/2015 09:27 AM, Chin Liang See wrote:
> On Wed, 2015-09-02 at 12:32 +0200, marex at denx.de wrote:

[snip]

>>>>>
>>>>> Would want to hear more from Jaehoon as Exynos and SOCFPGA are the one
>>>>> setting up these values.
>>>>
>>>> Since this approach is not based on dwmmc TRM, it's based on SOCFPGA SoC,
>>>> i think that it doesn't need to include into dwmmc core.
>>>> If need to located into dwmmc core, this code needs to modify more.
>>>>
>>>> As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not core
>>>> feature. Other SoC can't be used them. we don't know.
>>>
>>> Plus the way that this function is implemented, it is very specific to
>>> SoCFGA, as the tables and rows are representing 45 degree increments for
>>> the drvsel and smplsel value. Other platforms can have either more or
>>> less granularity in the drvsel and smplsel values.
>>
>> How is this SMPLSEL and DRVSEL implemented on Exynos ?

Exynos is using CLKSEL register in dw-mmc controller.
It's exynos specific register in dwmmc controller. It's also represented 45 degree increment.
SELCK_DRV is bit[18:16] or more. SELCLK_SAMPLE is bit[2:0] or more. There are other bits relevant to tuning clock.
'_more_' means that it can be changed bandwidth.

Anyway, I think there is no right method about finding the best smplclk and drvsel.
If this is generic method, i will pick this. But i don't think so, and there is no benefit for exynos.

smplclk and drvsel value need to process the tuning sequence.
There is no tuning case at bootloader, since it's not implemented about HS200 or upper mode.

Clksel an drvsel value are passed by device tree.

Best Regards,
Jaehoon Chung

> 
> The value comes from device tree.
> 
> Thanks
> Chin Liang
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-03  5:30                                           ` Jaehoon Chung
@ 2015-09-03  9:37                                             ` Marek Vasut
  2015-09-03 14:06                                               ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-09-03  9:37 UTC (permalink / raw)
  To: u-boot

On Thursday, September 03, 2015 at 07:30:08 AM, Jaehoon Chung wrote:
> Hi,

Hi,

> On 09/03/2015 09:27 AM, Chin Liang See wrote:
> > On Wed, 2015-09-02 at 12:32 +0200, marex at denx.de wrote:
> [snip]

thanks

> >>>>> Would want to hear more from Jaehoon as Exynos and SOCFPGA are the
> >>>>> one setting up these values.
> >>>> 
> >>>> Since this approach is not based on dwmmc TRM, it's based on SOCFPGA
> >>>> SoC, i think that it doesn't need to include into dwmmc core.
> >>>> If need to located into dwmmc core, this code needs to modify more.
> >>>> 
> >>>> As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not core
> >>>> feature. Other SoC can't be used them. we don't know.
> >>> 
> >>> Plus the way that this function is implemented, it is very specific to
> >>> SoCFGA, as the tables and rows are representing 45 degree increments
> >>> for the drvsel and smplsel value. Other platforms can have either more
> >>> or less granularity in the drvsel and smplsel values.
> >> 
> >> How is this SMPLSEL and DRVSEL implemented on Exynos ?
> 
> Exynos is using CLKSEL register in dw-mmc controller.
> It's exynos specific register in dwmmc controller. It's also represented 45
> degree increment. SELCK_DRV is bit[18:16] or more. SELCLK_SAMPLE is
> bit[2:0] or more. There are other bits relevant to tuning clock. '_more_'
> means that it can be changed bandwidth.
> 
> Anyway, I think there is no right method about finding the best smplclk and
> drvsel. If this is generic method, i will pick this. But i don't think so,
> and there is no benefit for exynos.
> 
> smplclk and drvsel value need to process the tuning sequence.
> There is no tuning case at bootloader, since it's not implemented about
> HS200 or upper mode.
> 
> Clksel an drvsel value are passed by device tree.

In that case, maybe SoCFPGA should also pick those values from DT ? It would
keep the code simple and in case there is a problematic board, it could use
u-boot application to perform the tuning.

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-03  9:37                                             ` Marek Vasut
@ 2015-09-03 14:06                                               ` Chin Liang See
  2015-09-03 14:25                                                 ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-09-03 14:06 UTC (permalink / raw)
  To: u-boot

Hi,

On Thu, 2015-09-03 at 11:37 +0200, marex at denx.de wrote:
> On Thursday, September 03, 2015 at 07:30:08 AM, Jaehoon Chung wrote:
> > Hi,
> 
> Hi,
> 
> > On 09/03/2015 09:27 AM, Chin Liang See wrote:
> > > On Wed, 2015-09-02 at 12:32 +0200, marex at denx.de wrote:
> > [snip]
> 
> thanks
> 
> > >>>>> Would want to hear more from Jaehoon as Exynos and SOCFPGA are the
> > >>>>> one setting up these values.
> > >>>> 
> > >>>> Since this approach is not based on dwmmc TRM, it's based on SOCFPGA
> > >>>> SoC, i think that it doesn't need to include into dwmmc core.
> > >>>> If need to located into dwmmc core, this code needs to modify more.
> > >>>> 
> > >>>> As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not core
> > >>>> feature. Other SoC can't be used them. we don't know.
> > >>> 
> > >>> Plus the way that this function is implemented, it is very specific to
> > >>> SoCFGA, as the tables and rows are representing 45 degree increments
> > >>> for the drvsel and smplsel value. Other platforms can have either more
> > >>> or less granularity in the drvsel and smplsel values.
> > >> 
> > >> How is this SMPLSEL and DRVSEL implemented on Exynos ?
> > 
> > Exynos is using CLKSEL register in dw-mmc controller.
> > It's exynos specific register in dwmmc controller. It's also represented 45
> > degree increment. SELCK_DRV is bit[18:16] or more. SELCLK_SAMPLE is
> > bit[2:0] or more. There are other bits relevant to tuning clock. '_more_'
> > means that it can be changed bandwidth.
> > 
> > Anyway, I think there is no right method about finding the best smplclk and
> > drvsel. If this is generic method, i will pick this. But i don't think so,
> > and there is no benefit for exynos.
> > 
> > smplclk and drvsel value need to process the tuning sequence.
> > There is no tuning case at bootloader, since it's not implemented about
> > HS200 or upper mode.
> > 
> > Clksel an drvsel value are passed by device tree.
> 
> In that case, maybe SoCFPGA should also pick those values from DT ? It would
> keep the code simple and in case there is a problematic board, it could use
> u-boot application to perform the tuning.

I prefer not to do that as it narrows the supported use case for the
driver.

Thanks
Chin Liang

> 
> Best regards,
> Marek Vasut

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-03 14:06                                               ` Chin Liang See
@ 2015-09-03 14:25                                                 ` Marek Vasut
  2015-09-04 10:41                                                   ` Pavel Machek
  0 siblings, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-09-03 14:25 UTC (permalink / raw)
  To: u-boot

On Thursday, September 03, 2015 at 04:06:12 PM, Chin Liang See wrote:
> Hi,
> 
> On Thu, 2015-09-03 at 11:37 +0200, marex at denx.de wrote:
> > On Thursday, September 03, 2015 at 07:30:08 AM, Jaehoon Chung wrote:
> > > Hi,
> > 
> > Hi,
> > 
> > > On 09/03/2015 09:27 AM, Chin Liang See wrote:
> > > > On Wed, 2015-09-02 at 12:32 +0200, marex at denx.de wrote:
> > > [snip]
> > 
> > thanks
> > 
> > > >>>>> Would want to hear more from Jaehoon as Exynos and SOCFPGA are
> > > >>>>> the one setting up these values.
> > > >>>> 
> > > >>>> Since this approach is not based on dwmmc TRM, it's based on
> > > >>>> SOCFPGA SoC, i think that it doesn't need to include into dwmmc
> > > >>>> core. If need to located into dwmmc core, this code needs to
> > > >>>> modify more.
> > > >>>> 
> > > >>>> As drvsel and clksmpl are used at Exynos and SoCFPGA, it's not
> > > >>>> core feature. Other SoC can't be used them. we don't know.
> > > >>> 
> > > >>> Plus the way that this function is implemented, it is very specific
> > > >>> to SoCFGA, as the tables and rows are representing 45 degree
> > > >>> increments for the drvsel and smplsel value. Other platforms can
> > > >>> have either more or less granularity in the drvsel and smplsel
> > > >>> values.
> > > >> 
> > > >> How is this SMPLSEL and DRVSEL implemented on Exynos ?
> > > 
> > > Exynos is using CLKSEL register in dw-mmc controller.
> > > It's exynos specific register in dwmmc controller. It's also
> > > represented 45 degree increment. SELCK_DRV is bit[18:16] or more.
> > > SELCLK_SAMPLE is bit[2:0] or more. There are other bits relevant to
> > > tuning clock. '_more_' means that it can be changed bandwidth.
> > > 
> > > Anyway, I think there is no right method about finding the best smplclk
> > > and drvsel. If this is generic method, i will pick this. But i don't
> > > think so, and there is no benefit for exynos.
> > > 
> > > smplclk and drvsel value need to process the tuning sequence.
> > > There is no tuning case at bootloader, since it's not implemented about
> > > HS200 or upper mode.
> > > 
> > > Clksel an drvsel value are passed by device tree.
> > 
> > In that case, maybe SoCFPGA should also pick those values from DT ? It
> > would keep the code simple and in case there is a problematic board, it
> > could use u-boot application to perform the tuning.
> 
> I prefer not to do that as it narrows the supported use case for the
> driver.

How so? It keeps the driver code clean and this code you're adding seems
like a special-purpose stuff which needs to be done once for particular
board, no ?

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-03 14:25                                                 ` Marek Vasut
@ 2015-09-04 10:41                                                   ` Pavel Machek
  2015-09-07  8:33                                                     ` Jaehoon Chung
  0 siblings, 1 reply; 40+ messages in thread
From: Pavel Machek @ 2015-09-04 10:41 UTC (permalink / raw)
  To: u-boot

Hi!

> > > > >> How is this SMPLSEL and DRVSEL implemented on Exynos ?
> > > > 
> > > > Exynos is using CLKSEL register in dw-mmc controller.
> > > > It's exynos specific register in dwmmc controller. It's also
> > > > represented 45 degree increment. SELCK_DRV is bit[18:16] or more.
> > > > SELCLK_SAMPLE is bit[2:0] or more. There are other bits relevant to
> > > > tuning clock. '_more_' means that it can be changed bandwidth.
> > > > 
> > > > Anyway, I think there is no right method about finding the best smplclk
> > > > and drvsel. If this is generic method, i will pick this. But i don't
> > > > think so, and there is no benefit for exynos.
> > > > 
> > > > smplclk and drvsel value need to process the tuning sequence.
> > > > There is no tuning case at bootloader, since it's not implemented about
> > > > HS200 or upper mode.
> > > > 
> > > > Clksel an drvsel value are passed by device tree.
> > > 
> > > In that case, maybe SoCFPGA should also pick those values from DT ? It
> > > would keep the code simple and in case there is a problematic board, it
> > > could use u-boot application to perform the tuning.
> > 
> > I prefer not to do that as it narrows the supported use case for the
> > driver.
> 
> How so? It keeps the driver code clean and this code you're adding seems
> like a special-purpose stuff which needs to be done once for particular
> board, no ?

Well... stuff that can be automatically detected is not supposed to be
in the device tree.

clksel and drvsel can be calibrated, so I see some arguments why we
should calibrate them, and not hardcode them in the device tree.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-04 10:41                                                   ` Pavel Machek
@ 2015-09-07  8:33                                                     ` Jaehoon Chung
  2015-09-08  1:32                                                       ` Chin Liang See
  0 siblings, 1 reply; 40+ messages in thread
From: Jaehoon Chung @ 2015-09-07  8:33 UTC (permalink / raw)
  To: u-boot

Hi,

On 09/04/2015 07:41 PM, Pavel Machek wrote:
> Hi!
> 
>>>>>>> How is this SMPLSEL and DRVSEL implemented on Exynos ?
>>>>>
>>>>> Exynos is using CLKSEL register in dw-mmc controller.
>>>>> It's exynos specific register in dwmmc controller. It's also
>>>>> represented 45 degree increment. SELCK_DRV is bit[18:16] or more.
>>>>> SELCLK_SAMPLE is bit[2:0] or more. There are other bits relevant to
>>>>> tuning clock. '_more_' means that it can be changed bandwidth.
>>>>>
>>>>> Anyway, I think there is no right method about finding the best smplclk
>>>>> and drvsel. If this is generic method, i will pick this. But i don't
>>>>> think so, and there is no benefit for exynos.
>>>>>
>>>>> smplclk and drvsel value need to process the tuning sequence.
>>>>> There is no tuning case at bootloader, since it's not implemented about
>>>>> HS200 or upper mode.
>>>>>
>>>>> Clksel an drvsel value are passed by device tree.
>>>>
>>>> In that case, maybe SoCFPGA should also pick those values from DT ? It
>>>> would keep the code simple and in case there is a problematic board, it
>>>> could use u-boot application to perform the tuning.
>>>
>>> I prefer not to do that as it narrows the supported use case for the
>>> driver.
>>
>> How so? It keeps the driver code clean and this code you're adding seems
>> like a special-purpose stuff which needs to be done once for particular
>> board, no ?
> 
> Well... stuff that can be automatically detected is not supposed to be
> in the device tree.
> 
> clksel and drvsel can be calibrated, so I see some arguments why we
> should calibrate them, and not hardcode them in the device tree.

My opinions are 

1. This code is not generic dwmmc code. So i don't want to locate into dwmmc core.
If need to apply, i agree that it applies this in socfpga-dw_mmc.c.

2. In exynos, value of devcie-tree is the tested value.
After has tested with every values, it defined the best value into device-tree.
(Working fine with values.)
At every time, it doesn't need to detect the best value with same SoC.
(Especially, at bootloader)

3. In my experiment, there should be side-effect during finding best sample/drv value.

4. If HS200 or upper mode is supported at bootloader, it needs the tuning sequence.
Then it needs to find the best sampl/drv values. but it doesn't support HS200 or other at bootloader.

5. Affect at booting time??


Best Regards,
Jaehoon Chung

> 									Pavel
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-07  8:33                                                     ` Jaehoon Chung
@ 2015-09-08  1:32                                                       ` Chin Liang See
  2015-09-08 10:56                                                         ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-09-08  1:32 UTC (permalink / raw)
  To: u-boot

Hi,

On Mon, 2015-09-07 at 03:33 +0000, Jaehoon Chung wrote:
> Hi,
> 
> On 09/04/2015 07:41 PM, Pavel Machek wrote:
> > Hi!
> > 
> >>>>>>> How is this SMPLSEL and DRVSEL implemented on Exynos ?
> >>>>>
> >>>>> Exynos is using CLKSEL register in dw-mmc controller.
> >>>>> It's exynos specific register in dwmmc controller. It's also
> >>>>> represented 45 degree increment. SELCK_DRV is bit[18:16] or more.
> >>>>> SELCLK_SAMPLE is bit[2:0] or more. There are other bits relevant to
> >>>>> tuning clock. '_more_' means that it can be changed bandwidth.
> >>>>>
> >>>>> Anyway, I think there is no right method about finding the best smplclk
> >>>>> and drvsel. If this is generic method, i will pick this. But i don't
> >>>>> think so, and there is no benefit for exynos.
> >>>>>
> >>>>> smplclk and drvsel value need to process the tuning sequence.
> >>>>> There is no tuning case at bootloader, since it's not implemented about
> >>>>> HS200 or upper mode.
> >>>>>
> >>>>> Clksel an drvsel value are passed by device tree.
> >>>>
> >>>> In that case, maybe SoCFPGA should also pick those values from DT ? It
> >>>> would keep the code simple and in case there is a problematic board, it
> >>>> could use u-boot application to perform the tuning.
> >>>
> >>> I prefer not to do that as it narrows the supported use case for the
> >>> driver.
> >>
> >> How so? It keeps the driver code clean and this code you're adding seems
> >> like a special-purpose stuff which needs to be done once for particular
> >> board, no ?
> > 
> > Well... stuff that can be automatically detected is not supposed to be
> > in the device tree.
> > 
> > clksel and drvsel can be calibrated, so I see some arguments why we
> > should calibrate them, and not hardcode them in the device tree.
> 
> My opinions are 
> 
> 1. This code is not generic dwmmc code. So i don't want to locate into dwmmc core.
> If need to apply, i agree that it applies this in socfpga-dw_mmc.c.
> 

Yup, let move that to socfpga-dw_mmc.c as majority believe that is
correct way to move forward. I shall send in v3 which integrate Pavel's
comment in v2

> 2. In exynos, value of devcie-tree is the tested value.
> After has tested with every values, it defined the best value into device-tree.
> (Working fine with values.)
> At every time, it doesn't need to detect the best value with same SoC.
> (Especially, at bootloader)
> 
> 3. In my experiment, there should be side-effect during finding best sample/drv value.
> 
> 4. If HS200 or upper mode is supported at bootloader, it needs the tuning sequence.
> Then it needs to find the best sampl/drv values. but it doesn't support HS200 or other at bootloader.
> 

Yah, normally it will not need that.
As we are catering for various customer board design, this calibration
will help even they routed the SDMMC slot few inches away.

> 5. Affect at booting time??

We measured this before and it took around ~5.2ms for worst case.

Thanks
Chin Liang

> 
> 
> Best Regards,
> Jaehoon Chung
> 
> > 									Pavel
> > 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-09-08  1:32                                                       ` Chin Liang See
@ 2015-09-08 10:56                                                         ` Marek Vasut
       [not found]                                                           ` <0016CF5815A1B142902817051AF62EB305FDF5BA@PG-ITEXCH01.altera.priv.altera.com>
  0 siblings, 1 reply; 40+ messages in thread
From: Marek Vasut @ 2015-09-08 10:56 UTC (permalink / raw)
  To: u-boot

On Tuesday, September 08, 2015 at 03:32:33 AM, Chin Liang See wrote:
> Hi,

Hi,

> On Mon, 2015-09-07 at 03:33 +0000, Jaehoon Chung wrote:
> > Hi,
> > 
> > On 09/04/2015 07:41 PM, Pavel Machek wrote:
> > > Hi!
> > > 
> > >>>>>>> How is this SMPLSEL and DRVSEL implemented on Exynos ?
> > >>>>> 
> > >>>>> Exynos is using CLKSEL register in dw-mmc controller.
> > >>>>> It's exynos specific register in dwmmc controller. It's also
> > >>>>> represented 45 degree increment. SELCK_DRV is bit[18:16] or more.
> > >>>>> SELCLK_SAMPLE is bit[2:0] or more. There are other bits relevant to
> > >>>>> tuning clock. '_more_' means that it can be changed bandwidth.
> > >>>>> 
> > >>>>> Anyway, I think there is no right method about finding the best
> > >>>>> smplclk and drvsel. If this is generic method, i will pick this.
> > >>>>> But i don't think so, and there is no benefit for exynos.
> > >>>>> 
> > >>>>> smplclk and drvsel value need to process the tuning sequence.
> > >>>>> There is no tuning case at bootloader, since it's not implemented
> > >>>>> about HS200 or upper mode.
> > >>>>> 
> > >>>>> Clksel an drvsel value are passed by device tree.
> > >>>> 
> > >>>> In that case, maybe SoCFPGA should also pick those values from DT ?
> > >>>> It would keep the code simple and in case there is a problematic
> > >>>> board, it could use u-boot application to perform the tuning.
> > >>> 
> > >>> I prefer not to do that as it narrows the supported use case for the
> > >>> driver.
> > >> 
> > >> How so? It keeps the driver code clean and this code you're adding
> > >> seems like a special-purpose stuff which needs to be done once for
> > >> particular board, no ?
> > > 
> > > Well... stuff that can be automatically detected is not supposed to be
> > > in the device tree.
> > > 
> > > clksel and drvsel can be calibrated, so I see some arguments why we
> > > should calibrate them, and not hardcode them in the device tree.
> > 
> > My opinions are
> > 
> > 1. This code is not generic dwmmc code. So i don't want to locate into
> > dwmmc core. If need to apply, i agree that it applies this in
> > socfpga-dw_mmc.c.
> 
> Yup, let move that to socfpga-dw_mmc.c as majority believe that is
> correct way to move forward. I shall send in v3 which integrate Pavel's
> comment in v2
> 
> > 2. In exynos, value of devcie-tree is the tested value.
> > After has tested with every values, it defined the best value into
> > device-tree. (Working fine with values.)
> > At every time, it doesn't need to detect the best value with same SoC.
> > (Especially, at bootloader)
> > 
> > 3. In my experiment, there should be side-effect during finding best
> > sample/drv value.
> > 
> > 4. If HS200 or upper mode is supported at bootloader, it needs the tuning
> > sequence. Then it needs to find the best sampl/drv values. but it
> > doesn't support HS200 or other at bootloader.
> 
> Yah, normally it will not need that.
> As we are catering for various customer board design, this calibration
> will help even they routed the SDMMC slot few inches away.
> 
> > 5. Affect at booting time??
> 
> We measured this before and it took around ~5.2ms for worst case.

Hm, what about supporting both the DT variant (where you specify drvsel and
smplsel in DT, the way we do it in Linux) and this calibration variant. The
calibration would only be executed if the smplsel and drvsel args were missing
from the DT.

What do you think ?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
       [not found]                                                           ` <0016CF5815A1B142902817051AF62EB305FDF5BA@PG-ITEXCH01.altera.priv.altera.com>
@ 2015-10-07  2:54                                                             ` Chin Liang See
  2015-10-12 14:44                                                               ` Marek Vasut
  0 siblings, 1 reply; 40+ messages in thread
From: Chin Liang See @ 2015-10-07  2:54 UTC (permalink / raw)
  To: u-boot

Hi Marek,

> On Tuesday, September 08, 2015 at 03:32:33 AM, Chin Liang See wrote:
> > Hi,
> 
> Hi,
> 
> > On Mon, 2015-09-07 at 03:33 +0000, Jaehoon Chung wrote:
> > > Hi,
> > > 
> > > On 09/04/2015 07:41 PM, Pavel Machek wrote:
> > > > Hi!
> > > > 
> > > >>>>>>> How is this SMPLSEL and DRVSEL implemented on Exynos ?
> > > >>>>> 
> > > >>>>> Exynos is using CLKSEL register in dw-mmc controller.
> > > >>>>> It's exynos specific register in dwmmc controller. It's also 
> > > >>>>> represented 45 degree increment. SELCK_DRV is bit[18:16] or more.
> > > >>>>> SELCLK_SAMPLE is bit[2:0] or more. There are other bits 
> > > >>>>> relevant to tuning clock. '_more_' means that it can be changed bandwidth.
> > > >>>>> 
> > > >>>>> Anyway, I think there is no right method about finding the 
> > > >>>>> best smplclk and drvsel. If this is generic method, i will pick this.
> > > >>>>> But i don't think so, and there is no benefit for exynos.
> > > >>>>> 
> > > >>>>> smplclk and drvsel value need to process the tuning sequence.
> > > >>>>> There is no tuning case at bootloader, since it's not 
> > > >>>>> implemented about HS200 or upper mode.
> > > >>>>> 
> > > >>>>> Clksel an drvsel value are passed by device tree.
> > > >>>> 
> > > >>>> In that case, maybe SoCFPGA should also pick those values from DT ?
> > > >>>> It would keep the code simple and in case there is a 
> > > >>>> problematic board, it could use u-boot application to perform the tuning.
> > > >>> 
> > > >>> I prefer not to do that as it narrows the supported use case for 
> > > >>> the driver.
> > > >> 
> > > >> How so? It keeps the driver code clean and this code you're 
> > > >> adding seems like a special-purpose stuff which needs to be done 
> > > >> once for particular board, no ?
> > > > 
> > > > Well... stuff that can be automatically detected is not supposed 
> > > > to be in the device tree.
> > > > 
> > > > clksel and drvsel can be calibrated, so I see some arguments why 
> > > > we should calibrate them, and not hardcode them in the device tree.
> > > 
> > > My opinions are
> > > 
> > > 1. This code is not generic dwmmc code. So i don't want to locate 
> > > into dwmmc core. If need to apply, i agree that it applies this in 
> > > socfpga-dw_mmc.c.
> > 
> > Yup, let move that to socfpga-dw_mmc.c as majority believe that is 
> > correct way to move forward. I shall send in v3 which integrate 
> > Pavel's comment in v2
> > 
> > > 2. In exynos, value of devcie-tree is the tested value.
> > > After has tested with every values, it defined the best value into 
> > > device-tree. (Working fine with values.) At every time, it doesn't 
> > > need to detect the best value with same SoC.
> > > (Especially, at bootloader)
> > > 
> > > 3. In my experiment, there should be side-effect during finding best 
> > > sample/drv value.
> > > 
> > > 4. If HS200 or upper mode is supported at bootloader, it needs the 
> > > tuning sequence. Then it needs to find the best sampl/drv values. 
> > > but it doesn't support HS200 or other at bootloader.
> > 
> > Yah, normally it will not need that.
> > As we are catering for various customer board design, this calibration 
> > will help even they routed the SDMMC slot few inches away.
> > 
> > > 5. Affect at booting time??
> > 
> > We measured this before and it took around ~5.2ms for worst case.
> 
> Hm, what about supporting both the DT variant (where you specify drvsel and smplsel in DT, the way we do it in Linux) and this calibration variant. The calibration would only be executed if the smplsel and drvsel args were missing from the DT.
> 
> What do you think ?

Sorry as missing out this email.
Yah, this sound good to me where user can use DT variant if concern
about the boot time. Let me create that and sending in new revision.

Thanks
Chin Liang

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel
  2015-10-07  2:54                                                             ` Chin Liang See
@ 2015-10-12 14:44                                                               ` Marek Vasut
  0 siblings, 0 replies; 40+ messages in thread
From: Marek Vasut @ 2015-10-12 14:44 UTC (permalink / raw)
  To: u-boot

On Wednesday, October 07, 2015 at 04:54:25 AM, Chin Liang See wrote:
> Hi Marek,

Hi!

> > > > 5. Affect at booting time??
> > > 
> > > We measured this before and it took around ~5.2ms for worst case.
> > 
> > Hm, what about supporting both the DT variant (where you specify drvsel
> > and smplsel in DT, the way we do it in Linux) and this calibration
> > variant. The calibration would only be executed if the smplsel and
> > drvsel args were missing from the DT.
> > 
> > What do you think ?
> 
> Sorry as missing out this email.

No problem, I was also pretty busy myself.

> Yah, this sound good to me where user can use DT variant if concern
> about the boot time. Let me create that and sending in new revision.

Thanks!

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2015-10-12 14:44 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-19  5:54 [U-Boot] [PATCH 1/2] arm: socfpga: mmc: Enable calibration for drvsel and smpsel Chin Liang See
2015-08-19  7:26 ` Pavel Machek
2015-08-19  7:34   ` Marek Vasut
2015-08-19  8:30     ` Chin Liang See
2015-08-19 23:23       ` Marek Vasut
2015-08-19  8:33   ` Chin Liang See
2015-08-19  7:40 ` Marek Vasut
2015-08-19  8:21   ` Chin Liang See
2015-08-19 19:36     ` Marek Vasut
2015-08-20  5:28       ` Chin Liang See
2015-08-20  5:32         ` Marek Vasut
2015-08-20 21:55           ` Dinh Nguyen
2015-08-20 21:59             ` Marek Vasut
2015-08-21  0:33               ` Dinh Nguyen
2015-08-21  0:42                 ` Marek Vasut
2015-08-21 20:52             ` Simon Glass
2015-08-24 15:04               ` Chin Liang See
2015-08-25  2:36                 ` Jaehoon Chung
2015-08-25  3:08                   ` Chin Liang See
2015-08-26  5:29                     ` Jaehoon Chung
2015-08-26  5:47                       ` Chin Liang See
2015-08-26  6:14                         ` Jaehoon Chung
2015-08-26  6:54                           ` Chin Liang See
2015-09-01  8:54                             ` Chin Liang See
2015-09-01  9:01                               ` Marek Vasut
2015-09-01  9:10                                 ` Chin Liang See
2015-09-01 10:12                                   ` Jaehoon Chung
2015-09-01 14:53                                     ` Dinh Nguyen
2015-09-02 10:32                                       ` Marek Vasut
2015-09-03  0:27                                         ` Chin Liang See
2015-09-03  5:30                                           ` Jaehoon Chung
2015-09-03  9:37                                             ` Marek Vasut
2015-09-03 14:06                                               ` Chin Liang See
2015-09-03 14:25                                                 ` Marek Vasut
2015-09-04 10:41                                                   ` Pavel Machek
2015-09-07  8:33                                                     ` Jaehoon Chung
2015-09-08  1:32                                                       ` Chin Liang See
2015-09-08 10:56                                                         ` Marek Vasut
     [not found]                                                           ` <0016CF5815A1B142902817051AF62EB305FDF5BA@PG-ITEXCH01.altera.priv.altera.com>
2015-10-07  2:54                                                             ` Chin Liang See
2015-10-12 14:44                                                               ` Marek Vasut

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.