summaryrefslogtreecommitdiffstats
path: root/src/soc/intel/common/block/scs/early_mmc.c
blob: 57f39f02e34ab4c75ca9204ae19210fb20dabcca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* SPDX-License-Identifier: GPL-2.0-only */
/* This file is part of the coreboot project. */

#include <acpi/acpi.h>
#include <cbmem.h>
#include <commonlib/storage/sd_mmc.h>
#include <commonlib/sd_mmc_ctrlr.h>
#include <commonlib/sdhci.h>
#include <compiler.h>
#include <console/console.h>
#include <device/pci.h>
#include <intelblocks/mmc.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <string.h>

void soc_sd_mmc_controller_quirks(struct sd_mmc_ctrlr *ctrlr)
{
	uint32_t f_min, f_max;

	if (soc_get_mmc_frequencies(&f_min, &f_max) < 0) {
		printk(BIOS_ERR,
			"MMC early init: failed to get mmc frequencies\n");
		return;
	}

	ctrlr->f_min = f_min;
	ctrlr->f_max = f_max;
}

static void enable_mmc_controller_bar(void)
{
	pci_write_config32(PCH_DEV_EMMC, PCI_BASE_ADDRESS_0,
				PRERAM_MMC_BASE_ADDRESS);
	pci_write_config16(PCH_DEV_EMMC, PCI_COMMAND,
				PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
}

static void disable_mmc_controller_bar(void)
{
	pci_write_config32(PCH_DEV_EMMC, PCI_BASE_ADDRESS_0, 0);
	pci_write_config16(PCH_DEV_EMMC, PCI_COMMAND,
				~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY));
}

static void set_early_mmc_wake_status(int32_t status)
{
	int32_t *ms_cbmem;

	ms_cbmem = cbmem_add(CBMEM_ID_MMC_STATUS, sizeof(int));

	if (ms_cbmem == NULL) {
		printk(BIOS_ERR,
			"%s: Failed to add early mmc wake status to cbmem!\n",
			__func__);
		return;
	}

	*ms_cbmem = status;
}

int early_mmc_wake_hw(void)
{
	struct storage_media media;
	struct sd_mmc_ctrlr *mmc_ctrlr;
	struct sdhci_ctrlr *sdhci_ctrlr;
	int err;

	if (acpi_is_wakeup_s3())
		return -1;

	/* Configure mmc gpios */
	if (soc_configure_mmc_gpios() < 0) {
		printk(BIOS_ERR,
			"%s: MMC early init: failed to configure mmc gpios\n",
			__func__);
		return -1;
	}
	/* Setup pci bar */
	enable_mmc_controller_bar();

	/* Initialize sdhci */
	mmc_ctrlr = new_pci_sdhci_controller(PCH_DEV_EMMC);
	if (mmc_ctrlr == NULL)
		goto out_err;

	sdhci_ctrlr = container_of(mmc_ctrlr, struct sdhci_ctrlr, sd_mmc_ctrlr);

	/* set emmc DLL tuning parameters */
	if (set_mmc_dll(sdhci_ctrlr->ioaddr) < 0)
		goto out_err;

	memset(&media, 0, sizeof(media));
	media.ctrlr = mmc_ctrlr;
	SET_BUS_WIDTH(mmc_ctrlr, 1);
	/*
	 * Set clock to 1 so that the driver can choose minimum frequency
	 * possible
	 */
	SET_CLOCK(mmc_ctrlr, 1);

	/* Reset emmc, send CMD0 */
	if (sd_mmc_go_idle(&media))
		goto out_err;

	/* Send CMD1 */
	err = mmc_send_op_cond(&media);
	if (err != 0 && err != CARD_IN_PROGRESS)
		goto out_err;

	disable_mmc_controller_bar();

	set_early_mmc_wake_status(1);
	return 0;

out_err:

	disable_mmc_controller_bar();
	return -1;
}