/* Copyright 2019 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/*
 * Chrome EC chipset power control for Cometlake with platform-controlled
 * discrete sequencing.
 */

#include "adc.h"
#include "chipset.h"
#include "console.h"
#include "gpio.h"
#include "intel_x86.h"
#include "power.h"
#include "power_button.h"
#include "task.h"
#include "timer.h"

/* Console output macros */
#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ##args)

/* Power signals list. Must match order of enum power_signal. */
const struct power_signal_info power_signal_list[] = {
	[PP5000_A_PGOOD] = {
		GPIO_PG_PP5000_A_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"PP5000_A_PGOOD",
	},
	[PP1800_A_PGOOD] = {
		GPIO_PG_PP1800_A_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"PP1800_A_PGOOD",
	},
	[VPRIM_CORE_A_PGOOD] = {
		GPIO_PG_VPRIM_CORE_A_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"VPRIM_CORE_A_PGOOD",
	},
	[PP1050_A_PGOOD] = {
		GPIO_PG_PP1050_A_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"PP1050_A_PGOOD",
	},
	[OUT_PCH_RSMRST_DEASSERTED] = {
		GPIO_PCH_RSMRST_L,
		POWER_SIGNAL_ACTIVE_HIGH,
		"OUT_PCH_RSMRST_DEASSERTED",
	},
	[X86_SLP_S4_DEASSERTED] = {
		SLP_S4_SIGNAL_L,
		POWER_SIGNAL_ACTIVE_HIGH,
		"SLP_S4_DEASSERTED",
	},
	[PP2500_DRAM_PGOOD] = {
		GPIO_PG_PP2500_DRAM_U_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"PP2500_DRAM_PGOOD",
	},
	[PP1200_DRAM_PGOOD] = {
		GPIO_PG_PP1200_U_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"PP1200_DRAM_PGOOD",
	},
	[X86_SLP_S3_DEASSERTED] = {
		SLP_S3_SIGNAL_L,
		POWER_SIGNAL_ACTIVE_HIGH,
		"SLP_S3_DEASSERTED",
	},
	[PP950_VCCIO_PGOOD] = {
		GPIO_PG_PP950_VCCIO_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"PP950_VCCIO_PGOOD",
	},
	[X86_SLP_S0_DEASSERTED] = {
		GPIO_PCH_SLP_S0_L,
		POWER_SIGNAL_ACTIVE_HIGH | POWER_SIGNAL_DISABLE_AT_BOOT,
		"SLP_S0_DEASSERTED",
	},
	[CPU_C10_GATE_DEASSERTED] = {
		GPIO_CPU_C10_GATE_L,
		POWER_SIGNAL_ACTIVE_HIGH,
		"CPU_C10_GATE_DEASSERTED",
	},
	[IMVP8_READY] = {
		GPIO_IMVP8_VRRDY_OD,
		POWER_SIGNAL_ACTIVE_HIGH,
		"IMVP8_READY",
	},
};
BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);

/*
 * The EC is responsible for most of the power-on sequence with this driver,
 * enabling rails and waiting for power-good signals from regulators before
 * continuing. The power sequencing works as follows.
 *
 * 1. From G3 (all-off), power is applied and EC power supplies come up.
 *    The power button task kicks off platform power-up as desired.
 * 2. Power up the platform to reach S5
 *   a. Enable PP5000_A and wait for PP5000_A_PGOOD.
 *   b. Enable PP3300_A (EN_ROA_RAILS).
 *   c. Wait for PP3300_A power good. This regulator doesn't provide a power
 *      good output, so the EC monitors ADC_SNS_PP3300.
 *   d. Enable PP1800_A and wait for PP1800_A_PGOOD.
 *   e. PP1800_A_PGOOD automatically enables PPVAR_VPRIM_CORE_A, which receives
 *      power from PP3300_A (hence PP3300_A must precede PP1800_A, even though
 *      PP1800_A draws power from PP3300_G which is guaranteed to already be on)
 *   f. PPVAR_VPRIM_CORE_A_PGOOD automatically enables PP1050_A
 *   g. Wait for PP1050_A_PGOOD, indicating that both PPVAR_VPRIM_CORE_A and
 *      PP1050_A are good.
 *   h. Wait 10ms to satisfy tPCH03, then bring the PCH out of reset by
 *      deasserting RSMRST.
 * 3. The PCH controls transition from S5 up to S3 and higher-power states.
 *   a. PCH deasserts SLP_S4, automatically turning on PP2500_DRAM_U and
 *      PP1200_DRAM_U.
 *   b. Wait for PP2500_DRAM_PGOOD and PP1200_DRAM_PGOOD.
 * 4. PCH deasserts SLP_S3 to switch to S0
 *   a. SLP_S3 transition automatically enables PP1050_ST_S.
 *   b. Wait for PP1050_ST_S good. The power good output from this regulator is
 *      not connected, so the EC monitors ADC_SNS_PP1050_ST_S.
 *   c. Turn on EN_S0_RAILS (enabling PP1200_PLLOC and PP1050_STG).
 *      VCCIO must not ramp up before VCCST, VCCSTG and memory rails are good
 *      (PDG figure 424, note 14).
 *   d. Wait 2ms (for EN_S0_RAILS load switches to turn on).
 *   e. Enable PP950_VCCIO.
 *   f. Wait for PG_PP950_VCCIO. Although the PCH may be asserting CPU_C10_GATED
 *      which holds the VCCIO regulator in a low-power mode, the regulator will
 *      turn on normally and assert power good then drop into low power mode
 *      and continue asserting power good.
 * 5. Transition fully to S0 following SLP_S0
 *   a. Assert VCCST_PWRGD. This notionally tracks PP1050_ST_S but must be
 *      deasserted in S3 and lower.
 *   b. Enable IMVP8_VR.
 *   c. Wait 2ms.
 *   d. Assert SYS_PWROK.
 *   e. Wait for IMVP8_VRRDY.
 *   f. Wait 2ms.
 *   g. Assert PCH_PWROK.
 *
 * When CPU_C10_GATED is asserted, we are free to disable PP1200_PLLOC and
 * PP1050_STG by deasserting EN_S0_RAILS to save some power. VCCIO is
 * automatically placed in low-power mode by CPU_C10_GATED, and no further
 * action is required- power-good signals will not change, just the relevant
 * load switches (which are specified to meet the platform's minimum turn-on
 * time when CPU_C10_GATED is deasserted again) are turned off. This gating is
 * done asynchronously.
 *
 * For further reference, Figure 421 and Table 370 in the Comet Lake U PDG
 * summarizes platform power rail requirements in a reasonably easy-to-digest
 * manner, while section 12.11 (containing those diagrams) details the required
 * operation.
 */

/*
 * Reverse of S0->S3 transition.
 *
 * This is a separate function so it can be reused when forcing shutdown due to
 * power failure or other reasons.
 */
static void shutdown_s0_rails(void)
{
	/*
	 * Deassert VCCST_PG as early as possible to satisfy tCPU22; VDDQ is
	 * derived directly from SLP_S3.
	 */
	gpio_set_level(GPIO_VCCST_PG_OD, 0);
	gpio_set_level(GPIO_EC_PCH_PWROK, 0);
	gpio_set_level(GPIO_EC_PCH_SYS_PWROK, 0);
	gpio_set_level(GPIO_EN_IMVP8_VR, 0);
	gpio_set_level(GPIO_EN_S0_RAILS, 0);
	usleep(1);	/* tPCH10: PCH_PWROK to VCCIO off >400 ns */
	gpio_set_level(GPIO_EN_PP950_VCCIO, 0);
}

/*
 * Reverse of G3->S5 transition.
 *
 * This is a separate function so it can be reused when forcing shutdown due to
 * power failure or other reasons.
 */
static void shutdown_s5_rails(void)
{
	gpio_set_level(GPIO_PCH_RSMRST_L, 0);
	/* tPCH12: RSMRST to VCCPRIM (PPVAR_VPRIM_CORE_A) off >400ns */
	usleep(1);
	gpio_set_level(GPIO_EN_PP1800_A, 0);
	gpio_set_level(GPIO_EN_ROA_RAILS, 0);
#ifdef CONFIG_POWER_PP5000_CONTROL
	power_5v_enable(task_get_current(), 0);
#else
	gpio_set_level(GPIO_EN_PP5000_A, 0);
#endif
}

void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
	CPRINTS("%s(%d)", __func__, reason);
	report_ap_reset(reason);

	shutdown_s0_rails();
	/* S3 is automatic based on SLP_S3 driving memory rails */
	shutdown_s5_rails();
}

void chipset_handle_espi_reset_assert(void)
{
	/*
	 * If eSPI_Reset# pin is asserted without SLP_SUS# being asserted, then
	 * it means that there is an unexpected power loss (global reset
	 * event). In this case, check if shutdown was being forced by pressing
	 * power button. If yes, release power button.
	 */
	if ((power_get_signals() & IN_PGOOD_ALL_CORE))
		power_button_pch_release();
}

enum power_state chipset_force_g3(void)
{
	chipset_force_shutdown(CHIPSET_SHUTDOWN_G3);

	return POWER_G3;
}

/*
 * Wait for a power rail on an analog channel to become good.
 *
 * @param channel	ADC channel to read
 * @param min_voltage	Minimum required voltage for rail (in mV)
 *
 * @return EC_SUCCESS, or non-zero if error.
 */
static int power_wait_analog(enum adc_channel channel, int min_voltage)
{
	timestamp_t deadline;
	int reading;

	/* One second timeout */
	deadline = get_time();
	deadline.val += SECOND;

	do {
		reading = adc_read_channel(channel);
		if (reading == ADC_READ_ERROR)
			return EC_ERROR_HW_INTERNAL;
		if (timestamp_expired(deadline, NULL))
			return EC_ERROR_TIMEOUT;
	} while (reading < min_voltage);

	return EC_SUCCESS;
}

/*
 * Force system power state if we time out waiting for a power rail to become
 * good.
 *
 * In general the new state is to transition down to the next lower-power state,
 * so if we time out in G3->S5 we return POWER_G3 to turn things off again and
 * if S3->S0 times out we return POWER_S3S5 for the same reason.
 *
 * Correct sequencing of rails that might already be enabled is handled by
 * chipset_force_shutdown(), so the caller of this function doesn't need to
 * clean up after itself.
 */
static enum power_state pgood_timeout(enum power_state new_state)
{
	chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
	return new_state;
}

/*
 * Called in the chipset task when power signal inputs change state.
 * If this doesn't request a different state, power_common_state handles it.
 *
 * @param state Current power state
 * @return New power state
 */
enum power_state power_handle_state(enum power_state state)
{
	/*
	 * TODO(b/144719399) gate PP1050_STG and PP1200_PLLOC when C10 asserted
	 * Puff proto also gates HDMI power on EN_S0_RAILS so for that board
	 * we do not gate them since HDMI should remain powered.
	 */

	switch (state) {
	case POWER_G3S5:
		/* Power-up steps 2a-2h. */
#ifdef CONFIG_POWER_PP5000_CONTROL
		power_5v_enable(task_get_current(), 1);
#else
		gpio_set_level(GPIO_EN_PP5000_A, 1);
#endif
		if (power_wait_signals(POWER_SIGNAL_MASK(PP5000_A_PGOOD)))
			return pgood_timeout(POWER_S5G3);
		gpio_set_level(GPIO_EN_ROA_RAILS, 1);
		if (power_wait_analog(ADC_SNS_PP3300, 3000) != EC_SUCCESS)
			return pgood_timeout(POWER_S5G3);
		gpio_set_level(GPIO_EN_PP1800_A, 1);
		if (power_wait_signals(POWER_SIGNAL_MASK(PP1800_A_PGOOD) |
				       POWER_SIGNAL_MASK(PP1050_A_PGOOD)))
			return pgood_timeout(POWER_S5G3);
		msleep(10);	/* tPCH03: VCCPRIM good -> RSMRST >10ms */
		gpio_set_level(GPIO_PCH_RSMRST_L, 1);
		break;

	case POWER_S5G3:
		shutdown_s5_rails();
		break;

	case POWER_S5S3:
		/* Power-up steps 3a-3b. */
		if (power_wait_signals(POWER_SIGNAL_MASK(PP2500_DRAM_PGOOD) |
				       POWER_SIGNAL_MASK(PP1200_DRAM_PGOOD)))
			return pgood_timeout(POWER_S3S5);
		break;

	case POWER_S3S0:
		/* Power-up steps 4a-4f. */
		if (power_wait_analog(ADC_SNS_PP1050, 1000) != EC_SUCCESS)
			return pgood_timeout(POWER_S3S5);
		gpio_set_level(GPIO_EN_S0_RAILS, 1);
		msleep(2);
		gpio_set_level(GPIO_EN_PP950_VCCIO, 1);
		if (power_wait_signals(POWER_SIGNAL_MASK(PP950_VCCIO_PGOOD)))
			return pgood_timeout(POWER_S3S5);

		/* Power-up steps 5a-5h */
		gpio_set_level(GPIO_VCCST_PG_OD, 1);
		gpio_set_level(GPIO_EN_IMVP8_VR, 1);
		msleep(2);
		gpio_set_level(GPIO_EC_PCH_SYS_PWROK, 1);
		if (power_wait_signals(POWER_SIGNAL_MASK(IMVP8_READY)))
			return pgood_timeout(POWER_S3S5);
		msleep(2);
		gpio_set_level(GPIO_EC_PCH_PWROK, 1);
		break;

	case POWER_S0S3:
		shutdown_s0_rails();
		break;

	default:
		break;
	}

	/*
	 * Power-up steps 3a-3b (S5->S3 via IN_PGOOD_ALL_CORE) plus general
	 * bookkeeping.
	 */
	return common_intel_x86_power_handle_state(state);
}
