/* Copyright (c) 2014 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. */ /* Dingdong dongle configuration */ #include "adc.h" #include "adc_chip.h" #include "common.h" #include "ec_version.h" #include "gpio.h" #include "hooks.h" #include "registers.h" #include "usb_bb.h" #include "usb_descriptor.h" #include "usb_pd.h" #include "task.h" #include "timer.h" #include "util.h" static volatile uint64_t hpd_prev_ts; static volatile int hpd_prev_level; void hpd_event(enum gpio_signal signal); #include "gpio_list.h" /** * Hotplug detect deferred task * * Called after level change on hpd GPIO to evaluate (and debounce) what event * has occurred. There are 3 events that occur on HPD: * 1. low : downstream display sink is deattached * 2. high : downstream display sink is attached * 3. irq : downstream display sink signalling an interrupt. * * The debounce times for these various events are: * HPD_USTREAM_DEBOUNCE_LVL : min pulse width of level value. * HPD_USTREAM_DEBOUNCE_IRQ : min pulse width of IRQ low pulse. * * lvl(n-2) lvl(n-1) lvl prev_delta now_delta event * ---------------------------------------------------- * 1 0 1 IRQ LVL high * 0 1 0 LVL low */ void hpd_irq_deferred(void) { pd_send_hpd(0, hpd_irq); } DECLARE_DEFERRED(hpd_irq_deferred); void hpd_lvl_deferred(void) { int level = gpio_get_level(GPIO_DP_HPD); if (level != hpd_prev_level) /* It's a glitch while in deferred or canceled action */ return; pd_send_hpd(0, (level) ? hpd_high : hpd_low); } DECLARE_DEFERRED(hpd_lvl_deferred); void hpd_event(enum gpio_signal signal) { timestamp_t now = get_time(); int level = gpio_get_level(signal); uint64_t cur_delta = now.val - hpd_prev_ts; /* store current time */ hpd_prev_ts = now.val; /* All previous hpd level events need to be re-triggered */ hook_call_deferred(&hpd_lvl_deferred_data, -1); /* It's a glitch. Previous time moves but level is the same. */ if (cur_delta < HPD_USTREAM_DEBOUNCE_IRQ) return; if ((!hpd_prev_level && level) && (cur_delta < HPD_USTREAM_DEBOUNCE_LVL)) /* It's an irq */ hook_call_deferred(&hpd_irq_deferred_data, 0); else if (cur_delta >= HPD_USTREAM_DEBOUNCE_LVL) hook_call_deferred(&hpd_lvl_deferred_data, HPD_USTREAM_DEBOUNCE_LVL); hpd_prev_level = level; } /* Initialize board. */ void board_config_pre_init(void) { /* enable SYSCFG clock */ STM32_RCC_APB2ENR |= 1 << 0; /* Remap USART DMA to match the USART driver */ STM32_SYSCFG_CFGR1 |= (1 << 9) | (1 << 10);/* Remap USART1 RX/TX DMA */ } /* Initialize board. */ static void board_init(void) { timestamp_t now = get_time(); hpd_prev_level = gpio_get_level(GPIO_DP_HPD); hpd_prev_ts = now.val; gpio_enable_interrupt(GPIO_DP_HPD); gpio_set_level(GPIO_STM_READY, 1); /* factory test only */ } DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); /* ADC channels */ const struct adc_t adc_channels[] = { /* USB PD CC lines sensing. Converted to mV (3300mV/4096). */ [ADC_CH_CC1_PD] = {"USB_C_CC1_PD", 3300, 4096, 0, STM32_AIN(1)}, }; BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); const void * const usb_strings[] = { [USB_STR_DESC] = usb_string_desc, [USB_STR_VENDOR] = USB_STRING_DESC("Google Inc."), [USB_STR_PRODUCT] = USB_STRING_DESC("Dingdong"), [USB_STR_VERSION] = USB_STRING_DESC(CROS_EC_VERSION32), [USB_STR_BB_URL] = USB_STRING_DESC(USB_GOOGLE_TYPEC_URL), }; BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT); /** * USB configuration * Any type-C device with alternate mode capabilities must have the following * set of descriptors. * * 1. Standard Device * 2. BOS * 2a. Container ID * 2b. Billboard Caps */ struct my_bos { struct usb_bos_hdr_descriptor bos; struct usb_contid_caps_descriptor contid_caps; struct usb_bb_caps_base_descriptor bb_caps; struct usb_bb_caps_svid_descriptor bb_caps_svids[1]; }; static struct my_bos bos_desc = { .bos = { .bLength = USB_DT_BOS_SIZE, .bDescriptorType = USB_DT_BOS, .wTotalLength = (USB_DT_BOS_SIZE + USB_DT_CONTID_SIZE + USB_BB_CAPS_BASE_SIZE + USB_BB_CAPS_SVID_SIZE * 1), .bNumDeviceCaps = 2, /* contid + bb_caps */ }, .contid_caps = { .bLength = USB_DT_CONTID_SIZE, .bDescriptorType = USB_DT_DEVICE_CAPABILITY, .bDevCapabilityType = USB_DC_DTYPE_CONTID, .bReserved = 0, .ContainerID = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }, .bb_caps = { .bLength = (USB_BB_CAPS_BASE_SIZE + USB_BB_CAPS_SVID_SIZE * 1), .bDescriptorType = USB_DT_DEVICE_CAPABILITY, .bDevCapabilityType = USB_DC_DTYPE_BILLBOARD, .iAdditionalInfoURL = USB_STR_BB_URL, .bNumberOfAlternateModes = 1, .bPreferredAlternateMode = 1, .VconnPower = 0, .bmConfigured = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, .bReserved = 0, }, .bb_caps_svids = { { .wSVID = USB_SID_DISPLAYPORT, .bAlternateMode = 1, .iAlternateModeString = USB_STR_BB_URL, /* TODO(crosbug.com/p/32687) */ }, }, }; const struct bos_context bos_ctx = { .descp = (void *)&bos_desc, .size = sizeof(struct my_bos), };