Merge changes Ia430dd32,I3b17cd2d

* changes:
  copper: Add support for fastboot and recovery keys
  copper: use dtb address from image header
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index c8c7e17..dbcd8dd 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -628,7 +628,6 @@
 			}
 
 			/* Read device device tree in the "tags_add */
-			hdr->tags_addr = 0x8400000;
 			if(mmc_read(ptn + offset + dt_entry_ptr->offset,
 						 (void *)hdr->tags_addr, dt_entry_ptr->size)) {
 				dprintf(CRITICAL, "ERROR: Cannot read device tree\n");
diff --git a/dev/pmic/pm8x41/include/pm8x41.h b/dev/pmic/pm8x41/include/pm8x41.h
index 411a063..e5a4b10 100644
--- a/dev/pmic/pm8x41/include/pm8x41.h
+++ b/dev/pmic/pm8x41/include/pm8x41.h
@@ -29,6 +29,34 @@
 #ifndef _PM8x41_H_
 #define _PM8x41_H_
 
+#define PM_GPIO_DIR_OUT         0x01
+#define PM_GPIO_DIR_IN          0x00
+#define PM_GPIO_DIR_BOTH        0x02
+
+#define PM_GPIO_PULL_UP_30      0
+#define PM_GPIO_PULL_UP_1_5     1
+#define PM_GPIO_PULL_UP_31_5    2
+/* 1.5uA + 30uA boost */
+#define PM_GPIO_PULL_UP_1_5_30  3
+#define PM_GPIO_PULL_RESV_1     4
+#define PM_GPIO_PULL_RESV_2     5
+
+struct pm8x41_gpio {
+	int direction;
+	int output_buffer;
+	int output_value;
+	int pull;
+	int vin_sel;
+	int out_strength;
+	int function;
+	int inv_int_pol;
+	int disable_pin;
+};
+
+int pm8x41_gpio_get(uint8_t gpio, uint8_t *status);
+int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config);
 void pm8x41_set_boot_done();
+int pm8x41_vol_down_key_status();
+
 
 #endif
diff --git a/dev/pmic/pm8x41/include/pm8x41_hw.h b/dev/pmic/pm8x41/include/pm8x41_hw.h
index 36dd422..0889bb9 100644
--- a/dev/pmic/pm8x41/include/pm8x41_hw.h
+++ b/dev/pmic/pm8x41/include/pm8x41_hw.h
@@ -29,14 +29,50 @@
 #ifndef _PM8x41_HW_H_
 #define _PM8x41_HW_H_
 
-/* Slave IDs */
-#define PM8x41_SMBB_SLAVE_ID                  0
 
-/* Peripheral Base Addresses */
-#define PM8x41_SMBB_PERIPHERAL_ID_BASE        0x1600
+/* SMBB Registers */
+#define SMBB_MISC_BOOT_DONE                   0x1642
 
-/* Register Offsets */
-#define SMBB_MISC_BOOT_DONE                   0x42
-#define BOOT_DONE_SHIFT                       7
+/* SMBB bit values */
+#define BOOT_DONE_BIT                         7
+
+
+/* GPIO Registers */
+#define GPIO_PERIPHERAL_BASE                  0xC000
+/* Peripheral base address for GPIO_X */
+#define GPIO_N_PERIPHERAL_BASE(x)            (GPIO_PERIPHERAL_BASE + ((x) - 1) * 0x100)
+
+/* Register offsets within GPIO */
+#define GPIO_STATUS                           0x08
+#define GPIO_MODE_CTL                         0x40
+#define GPIO_DIG_VIN_CTL                      0x41
+#define GPIO_DIG_PULL_CTL                     0x42
+#define GPIO_DIG_OUT_CTL                      0x45
+#define GPIO_EN_CTL                           0x46
+
+/* GPIO bit values */
+#define PERPH_EN_BIT                          7
+#define GPIO_STATUS_VAL_BIT                   0
+
+
+/* PON Peripheral registers */
+#define PON_INT_RT_STS                        0x810
+#define PON_INT_SET_TYPE                      0x811
+#define PON_INT_POLARITY_HIGH                 0x812
+#define PON_INT_POLARITY_LOW                  0x813
+#define PON_INT_LATCHED_CLR                   0x814
+#define PON_INT_EN_SET                        0x815
+#define PON_INT_LATCHED_STS                   0x818
+#define PON_INT_PENDING_STS                   0x819
+#define PON_RESIN_N_RESET_S1_TIMER            0x844  /* bits 0:3  : S1_TIMER */
+#define PON_RESIN_N_RESET_S2_TIMER            0x845  /* bits 0:2  : S2_TIMER */
+#define PON_RESIN_N_RESET_S2_CTL              0x846  /* bit 7: S2_RESET_EN, bit 0:3 : RESET_TYPE  */
+
+/* PON Peripheral register bit values */
+#define RESIN_BARK_INT_BIT                    4
+#define S2_RESET_EN_BIT                       7
+
+#define S2_RESET_TYPE_WARM                    0x1
+#define PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE  0x7
 
 #endif
diff --git a/dev/pmic/pm8x41/pm8x41.c b/dev/pmic/pm8x41/pm8x41.c
index d3b6cd1..4eac64f 100644
--- a/dev/pmic/pm8x41/pm8x41.c
+++ b/dev/pmic/pm8x41/pm8x41.c
@@ -26,28 +26,167 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <bits.h>
 #include <debug.h>
 #include <reg.h>
 #include <spmi.h>
 #include <pm8x41_hw.h>
+#include <pm8x41.h>
+#include <platform/timer.h>
 
-/* Function to set the boot done flag */
-void pm8x41_set_boot_done()
+/* Local Macros */
+#define REG_READ(_a)        pm8x41_reg_read(_a)
+#define REG_WRITE(_a, _v)   pm8x41_reg_write(_a, _v)
+
+#define REG_OFFSET(_addr)   ((_addr) & 0xFF)
+#define PERIPH_ID(_addr)    (((_addr) & 0xFF00) >> 8)
+#define SLAVE_ID(_addr)     ((_addr) >> 16)
+
+
+/* Local functions */
+static uint8_t pm8x41_reg_read(uint32_t addr)
+{
+	uint8_t val = 0;
+	struct pmic_arb_cmd cmd;
+	struct pmic_arb_param param;
+
+	cmd.address  = PERIPH_ID(addr);
+	cmd.offset   = REG_OFFSET(addr);
+	cmd.slave_id = SLAVE_ID(addr);
+	cmd.priority = 0;
+
+	param.buffer = &val;
+	param.size   = 1;
+
+	pmic_arb_read_cmd(&cmd, &param);
+
+	return val;
+}
+
+static void pm8x41_reg_write(uint32_t addr, uint8_t val)
 {
 	struct pmic_arb_cmd cmd;
 	struct pmic_arb_param param;
-	uint8_t boot_done;
 
-	cmd.address = ((uint16_t)(PM8x41_SMBB_PERIPHERAL_ID_BASE) >> 8);
-	cmd.offset = SMBB_MISC_BOOT_DONE;
+	cmd.address  = PERIPH_ID(addr);
+	cmd.offset   = REG_OFFSET(addr);
+	cmd.slave_id = SLAVE_ID(addr);
 	cmd.priority = 0;
-	cmd.slave_id = PM8x41_SMBB_SLAVE_ID;
 
-	/* Enable the module */
-	boot_done = 1 << BOOT_DONE_SHIFT;
-	param.buffer = &boot_done;
-	param.size = 1;
+	param.buffer = &val;
+	param.size   = 1;
 
-	pmic_arb_write_cmd(&cmd,&param);
+	pmic_arb_write_cmd(&cmd, &param);
+}
 
+/* Exported functions */
+
+/* Set the boot done flag */
+void pm8x41_set_boot_done()
+{
+	uint8_t val;
+
+	val  = REG_READ(SMBB_MISC_BOOT_DONE);
+	val |= BIT(BOOT_DONE_BIT);
+	REG_WRITE(SMBB_MISC_BOOT_DONE, val);
+}
+
+/* Configure GPIO */
+int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
+{
+	uint8_t  val;
+	uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
+
+	/* Disable the GPIO */
+	val  = REG_READ(gpio_base + GPIO_EN_CTL);
+	val &= ~BIT(PERPH_EN_BIT);
+	REG_WRITE(gpio_base + GPIO_EN_CTL, val);
+
+	/* Select the mode */
+	val = config->function | (config->direction << 4);
+	REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
+
+	/* Set the right pull */
+	val = config->pull;
+	REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
+
+	/* Select the VIN */
+	val = config->vin_sel;
+	REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
+
+	/* Enable the GPIO */
+	val  = REG_READ(gpio_base + GPIO_EN_CTL);
+	val |= BIT(PERPH_EN_BIT);
+	REG_WRITE(gpio_base + GPIO_EN_CTL, val);
+
+	return 1;
+}
+
+/* Reads the status of requested gpio */
+int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
+{
+	uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
+
+	*status = REG_READ(gpio_base + GPIO_STATUS);
+
+	/* Return the value of the GPIO pin */
+	*status &= BIT(GPIO_STATUS_VAL_BIT);
+
+	dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
+
+	return 1;
+}
+
+/* Prepare PON RESIN S2 reset */
+void pm8x41_vol_down_key_prepare()
+{
+	uint8_t val;
+
+	/* disable s2 reset */
+	REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
+
+	/* configure s1 timer to 0 */
+	REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
+
+	/* configure s2 timer to 2s */
+	REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
+
+	/* configure reset type */
+	REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
+
+	val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
+
+	/* enable s2 reset */
+	val |= BIT(S2_RESET_EN_BIT);
+	REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
+}
+
+/* Volume_Down key detect cleanup */
+void pm8x41_vol_down_key_done()
+{
+	/* disable s2 reset */
+	REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
+}
+
+/* Volume_Down key status */
+int pm8x41_vol_down_key_status()
+{
+	uint8_t rt_sts = 0;
+
+	/* Enable S2 reset so we can detect the volume down key press */
+	pm8x41_vol_down_key_prepare();
+
+	/* Delay before interrupt triggering.
+	 * See PON_DEBOUNCE_CTL reg.
+	 */
+	mdelay(100);
+
+	rt_sts = REG_READ(PON_INT_RT_STS);
+
+	/* Must disable S2 reset otherwise PMIC will reset if key
+	 * is held longer than S2 timer.
+	 */
+	pm8x41_vol_down_key_done();
+
+	return (rt_sts & BIT(RESIN_BARK_INT_BIT));
 }
diff --git a/target/copper/init.c b/target/copper/init.c
index 7e9f2c6..a11e23b 100644
--- a/target/copper/init.c
+++ b/target/copper/init.c
@@ -39,7 +39,8 @@
 #include <board.h>
 #include <smem.h>
 #include <baseband.h>
-
+#include <dev/keys.h>
+#include <pm8x41.h>
 
 static unsigned int target_id;
 
@@ -57,6 +58,50 @@
 #endif
 }
 
+/* Return 1 if vol_up pressed */
+static int target_volume_up()
+{
+	uint8_t status = 0;
+	struct pm8x41_gpio gpio;
+
+	/* CDP vol_up seems to be always grounded. So gpio status is read as 0,
+	 * whether key is pressed or not.
+	 * Ignore volume_up key on CDP for now.
+	 */
+	if (board_hardware_id() == HW_PLATFORM_SURF)
+		return 0;
+
+	/* Configure the GPIO */
+	gpio.direction = PM_GPIO_DIR_IN;
+	gpio.function  = 0;
+	gpio.pull      = PM_GPIO_PULL_UP_30;
+	gpio.vin_sel   = 0;
+
+	pm8x41_gpio_config(5, &gpio);
+
+	/* Get status of P_GPIO_5 */
+	pm8x41_gpio_get(5, &status);
+
+	return !status; /* active low */
+}
+
+/* Return 1 if vol_down pressed */
+int target_volume_down()
+{
+	return pm8x41_vol_down_key_status();
+}
+
+static void target_keystatus()
+{
+	keys_init();
+
+	if(target_volume_down())
+		keys_post_event(KEY_VOLUMEDOWN, 1);
+
+	if(target_volume_up())
+		keys_post_event(KEY_VOLUMEUP, 1);
+}
+
 void target_init(void)
 {
 	uint32_t base_addr;
@@ -67,6 +112,8 @@
 
 	spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);
 
+	target_keystatus();
+
 	/* Trying Slot 1*/
 	slot = 1;
 	base_addr = mmc_sdc_base[slot - 1];
@@ -91,7 +138,8 @@
 /* Do any target specific intialization needed before entering fastboot mode */
 void target_fastboot_init(void)
 {
-
+	/* Set the BOOT_DONE flag in PM8921 */
+	pm8x41_set_boot_done();
 }
 
 /* Detect the target type */
@@ -109,3 +157,12 @@
 	else
 		board->baseband = BASEBAND_MSM;
 }
+
+void target_serialno(unsigned char *buf)
+{
+	unsigned int serialno;
+	if (target_is_emmc_boot()) {
+		serialno = mmc_get_psn();
+		snprintf((char *)buf, 13, "%x", serialno);
+	}
+}