Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abcc6b29 authored by Micky Ching's avatar Micky Ching Committed by Chris Ball
Browse files

mmc: rtsx: modify phase searching method for tuning



The new phase searching method is more concise and easier to
understand.

Signed-off-by: default avatarMicky Ching <micky_ching@realsil.com.cn>
Signed-off-by: default avatarChris Ball <chris@printf.net>
parent 640e09bc
Loading
Loading
Loading
Loading
+32 −80
Original line number Diff line number Diff line
@@ -31,16 +31,6 @@
#include <linux/mfd/rtsx_pci.h>
#include <asm/unaligned.h>

/* SD Tuning Data Structure
 * Record continuous timing phase path
 */
struct timing_phase_path {
	int start;
	int end;
	int mid;
	int len;
};

struct realtek_pci_sdmmc {
	struct platform_device	*pdev;
	struct rtsx_pcr		*pcr;
@@ -511,85 +501,47 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
	return 0;
}

static inline u32 test_phase_bit(u32 phase_map, unsigned int bit)
{
	bit %= RTSX_PHASE_MAX;
	return phase_map & (1 << bit);
}

static int sd_get_phase_len(u32 phase_map, unsigned int start_bit)
{
	int i;

	for (i = 0; i < RTSX_PHASE_MAX; i++) {
		if (test_phase_bit(phase_map, start_bit + i) == 0)
			return i;
	}
	return RTSX_PHASE_MAX;
}

static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map)
{
	struct timing_phase_path path[MAX_PHASE + 1];
	int i, j, cont_path_cnt;
	int new_block, max_len, final_path_idx;
	int start = 0, len = 0;
	int start_final = 0, len_final = 0;
	u8 final_phase = 0xFF;

	/* Parse phase_map, take it as a bit-ring */
	cont_path_cnt = 0;
	new_block = 1;
	j = 0;
	for (i = 0; i < MAX_PHASE + 1; i++) {
		if (phase_map & (1 << i)) {
			if (new_block) {
				new_block = 0;
				j = cont_path_cnt++;
				path[j].start = i;
				path[j].end = i;
			} else {
				path[j].end = i;
			}
		} else {
			new_block = 1;
			if (cont_path_cnt) {
				/* Calculate path length and middle point */
				int idx = cont_path_cnt - 1;
				path[idx].len =
					path[idx].end - path[idx].start + 1;
				path[idx].mid =
					path[idx].start + path[idx].len / 2;
	if (phase_map == 0) {
		dev_err(sdmmc_dev(host), "phase error: [map:%x]\n", phase_map);
		return final_phase;
	}

	while (start < RTSX_PHASE_MAX) {
		len = sd_get_phase_len(phase_map, start);
		if (len_final < len) {
			start_final = start;
			len_final = len;
		}
		start += len ? len : 1;
	}

	if (cont_path_cnt == 0) {
		dev_dbg(sdmmc_dev(host), "No continuous phase path\n");
		goto finish;
	} else {
		/* Calculate last continuous path length and middle point */
		int idx = cont_path_cnt - 1;
		path[idx].len = path[idx].end - path[idx].start + 1;
		path[idx].mid = path[idx].start + path[idx].len / 2;
	}

	/* Connect the first and last continuous paths if they are adjacent */
	if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) {
		/* Using negative index */
		path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1;
		path[0].len += path[cont_path_cnt - 1].len;
		path[0].mid = path[0].start + path[0].len / 2;
		/* Convert negative middle point index to positive one */
		if (path[0].mid < 0)
			path[0].mid += MAX_PHASE + 1;
		cont_path_cnt--;
	}

	/* Choose the longest continuous phase path */
	max_len = 0;
	final_phase = 0;
	final_path_idx = 0;
	for (i = 0; i < cont_path_cnt; i++) {
		if (path[i].len > max_len) {
			max_len = path[i].len;
			final_phase = (u8)path[i].mid;
			final_path_idx = i;
		}

		dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n",
				i, path[i].start);
		dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n",
				i, path[i].end);
		dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n",
				i, path[i].len);
		dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n",
				i, path[i].mid);
	}
	final_phase = (start_final + len_final / 2) % RTSX_PHASE_MAX;
	dev_dbg(sdmmc_dev(host), "phase: [map:%x] [maxlen:%d] [final:%d]\n",
		phase_map, len_final, final_phase);

finish:
	dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase);
	return final_phase;
}

@@ -635,7 +587,7 @@ static int sd_tuning_phase(struct realtek_pci_sdmmc *host,
	int err, i;
	u32 raw_phase_map = 0;

	for (i = MAX_PHASE; i >= 0; i--) {
	for (i = 0; i < RTSX_PHASE_MAX; i++) {
		err = sd_tuning_rx_cmd(host, opcode, (u8)i);
		if (err == 0)
			raw_phase_map |= 1 << i;
+1 −1
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@
#define HOST_TO_DEVICE		0
#define DEVICE_TO_HOST		1

#define MAX_PHASE		31
#define RTSX_PHASE_MAX		32
#define RX_TUNING_CNT		3

/* SG descriptor */